Skip to content

[Epic] 1953-epic-desktop-transport-api - #1969

Merged
integry merged 4 commits into
1950-epic-cross-platform-dskfrom
1953-epic-desktop-transport-api
Aug 29, 2026
Merged

[Epic] 1953-epic-desktop-transport-api#1969
integry merged 4 commits into
1950-epic-cross-platform-dskfrom
1953-epic-desktop-transport-api

Conversation

@propr-dev

@propr-dev propr-dev Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Epic PR

This PR aggregates all changes from child PRs merged to the 1953-epic-desktop-transport-api branch.


Created automatically by ProPR

propr-dev[bot] and others added 4 commits August 29, 2026 14:28
…nstance conn

Implemented by ProPR AI using gpt-5.6-sol model.

Implementation completed successfully.
…compatibilit

Implemented by ProPR AI using gpt-5.6-sol model.

Implementation completed successfully.
…d-propr-api-20260829-1408-n3k

[1954 by GPT-5.6 Sol] Create a shared ProPR API client and instance connection model
…ktop-pairin-20260829-1408-o5i

[1955 by GPT-5.6 Sol] Add secure desktop pairing tokens and compatibility discovery to the API
@integry
integry changed the base branch from main to 1950-epic-cross-platform-dsk August 29, 2026 15:03
@integry
integry marked this pull request as ready for review August 29, 2026 15:04
@integry
integry merged commit f01d661 into 1950-epic-cross-platform-dsk Aug 29, 2026
18 of 19 checks passed
@github-actions

Copy link
Copy Markdown

Full Test Suite Results

Validation failed during: Full test suite.

  • Dependency install: success
  • Workspace build: success
  • Docs validation: success
  • Redis startup: success
  • Full test suite: failure
View Test Output

> propr@0.8.15 test:full:prepared
> npm run test:server


> propr@0.8.15 test:server
> node scripts/run-test-suite.mjs


[1/311] packages/api/test/agentLoginRoutes.test.ts
TAP version 13
# Subtest: agent login session manager
    # Subtest: builds an allowlisted Docker login container without forwarding host secrets
    ok 1 - builds an allowlisted Docker login container without forwarding host secrets
      ---
      duration_ms: 3.091899
      type: 'test'
      ...
    # Subtest: maps a ProPR-managed account to the managed host root and marks its container ownership as safe to normalize
    ok 2 - maps a ProPR-managed account to the managed host root and marks its container ownership as safe to normalize
      ---
      duration_ms: 1.386068
      type: 'test'
      ...
    # Subtest: creates a ProPR-managed credential directory before starting Docker
    ok 3 - creates a ProPR-managed credential directory before starting Docker
      ---
      duration_ms: 2.415099
      type: 'test'
      ...
    # Subtest: fails clearly instead of resolving a default home path inside a containerized API
    ok 4 - fails clearly instead of resolving a default home path inside a containerized API
      ---
      duration_ms: 0.658683
      type: 'test'
      ...
    # Subtest: rejects unsafe credential roots and option-like image names
    ok 5 - rejects unsafe credential roots and option-like image names
      ---
      duration_ms: 0.449554
      type: 'test'
      ...
    # Subtest: streams sanitized output, accepts input, and records successful completion
    ok 6 - streams sanitized output, accepts input, and records successful completion
      ---
      duration_ms: 1.70444
      type: 'test'
      ...
    # Subtest: prevents concurrent logins that write the same credential directory
    ok 7 - prevents concurrent logins that write the same credential directory
      ---
      duration_ms: 0.738892
      type: 'test'
      ...
    # Subtest: pulls a missing agent image before creating the login container
    ok 8 - pulls a missing agent image before creating the login container
      ---
      duration_ms: 0.659324
      type: 'test'
      ...
    # Subtest: renews the session deadline when the user sends input
    ok 9 - renews the session deadline when the user sends input
      ---
      duration_ms: 0.664072
      type: 'test'
      ...
    # Subtest: sweeps only orphaned login containers from the current stack scope
    ok 10 - sweeps only orphaned login containers from the current stack scope
      ---
      duration_ms: 0.597303
      type: 'test'
      ...
    1..10
ok 1 - agent login session manager
  ---
  duration_ms: 13.723813
  type: 'suite'
  ...
# Subtest: agent login routes
    # Subtest: starts and returns only the requesting user login session
    ok 1 - starts and returns only the requesting user login session
      ---
      duration_ms: 0.829406
      type: 'test'
      ...
    # Subtest: accepts the same agent alias on start and follow-up calls, including while disabled
    ok 2 - accepts the same agent alias on start and follow-up calls, including while disabled
      ---
      duration_ms: 0.588379
      type: 'test'
      ...
    # Subtest: rejects interactive login for an unsupported agent type
    ok 3 - rejects interactive login for an unsupported agent type
      ---
      duration_ms: 0.488482
      type: 'test'
      ...
    1..3
ok 2 - agent login routes
  ---
  duration_ms: 2.044111
  type: 'suite'
  ...
# [2026-08-29 15:06:01.500 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/001-agentLoginRoutes.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:01.512 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# [2026-08-29 15:06:01.512 +0000] �[32mINFO�[39m: �[36mShutting down queue...�[39m
# [2026-08-29 15:06:01.512 +0000] �[32mINFO�[39m: �[36mQueue was never initialized, nothing to shutdown�[39m
1..2
# tests 13
# suites 2
# pass 13
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2250.779513

[2/311] packages/api/test/agentRuntimeRoutes.test.ts
TAP version 13
# Subtest: agent runtime package routes
    # Subtest: queues one validated package profile for the unified agent image
    ok 1 - queues one validated package profile for the unified agent image
      ---
      duration_ms: 4.120199
      type: 'test'
      ...
    # Subtest: persists a failed state when queue submission fails
    ok 2 - persists a failed state when queue submission fails
      ---
      duration_ms: 0.917956
      type: 'test'
      ...
    # Subtest: rejects a package missing from an effective runtime before queueing
    ok 3 - rejects a package missing from an effective runtime before queueing
      ---
      duration_ms: 0.765301
      type: 'test'
      ...
    # Subtest: times out slow runtime package validation before queueing
    ok 4 - times out slow runtime package validation before queueing
      ---
      duration_ms: 6.475581
      type: 'test'
      ...
    # Subtest: returns package suggestions from configured runtimes
    ok 5 - returns package suggestions from configured runtimes
      ---
      duration_ms: 1.004314
      type: 'test'
      ...
    # Subtest: enforces PROPR_ADMIN_USERS when configured
    ok 6 - enforces PROPR_ADMIN_USERS when configured
      ---
      duration_ms: 0.42656
      type: 'test'
      ...
    # Subtest: denies runtime package changes by default when no admin policy is configured
    ok 7 - denies runtime package changes by default when no admin policy is configured
      ---
      duration_ms: 0.511746
      type: 'test'
      ...
    # Subtest: requires runtime-management permission before returning runtime package state
    ok 8 - requires runtime-management permission before returning runtime package state
      ---
      duration_ms: 0.518816
      type: 'test'
      ...
    # Subtest: warms the package catalog when an admin loads runtime package state
    ok 9 - warms the package catalog when an admin loads runtime package state
      ---
      duration_ms: 0.772812
      type: 'test'
      ...
    # Subtest: does not warm the package catalog when a member is rejected
    ok 10 - does not warm the package catalog when a member is rejected
      ---
      duration_ms: 2.545542
      type: 'test'
      ...
    # Subtest: resolves the runtime build queue lazily when queueing
    ok 11 - resolves the runtime build queue lazily when queueing
      ---
      duration_ms: 0.884527
      type: 'test'
      ...
    # Subtest: reports apply load failures through the route response
    ok 12 - reports apply load failures through the route response
      ---
      duration_ms: 0.463776
      type: 'test'
      ...
    # Subtest: verifies the current effective images through the runtime-management boundary
    ok 13 - verifies the current effective images through the runtime-management boundary
      ---
      duration_ms: 0.540749
      type: 'test'
      ...
    # Subtest: rejects runtime verification without runtime-management permission
    ok 14 - rejects runtime verification without runtime-management permission
      ---
      duration_ms: 0.272453
      type: 'test'
      ...
    1..14
ok 1 - agent runtime package routes
  ---
  duration_ms: 21.960907
  type: 'suite'
  ...
# [2026-08-29 15:06:03.514 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/002-agentRuntimeRoutes.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:03.533 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..1
# tests 14
# suites 1
# pass 14
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2063.48543

[3/311] packages/api/test/attachmentUploadCleanup.test.ts
TAP version 13
# Subtest: upload handler removes Multer files rejected before attachment processing
ok 1 - upload handler removes Multer files rejected before attachment processing
  ---
  duration_ms: 7.419746
  type: 'test'
  ...
# Subtest: attachment processing removes temporary and final files when persistence fails
ok 2 - attachment processing removes temporary and final files when persistence fails
  ---
  duration_ms: 5.411488
  type: 'test'
  ...
# Subtest: temporary cleanup refuses paths outside its configured root
ok 3 - temporary cleanup refuses paths outside its configured root
  ---
  duration_ms: 0.694176
  type: 'test'
  ...
# Subtest: temporary cleanup rejects dot-segment paths that resolve above its root
ok 4 - temporary cleanup rejects dot-segment paths that resolve above its root
  ---
  duration_ms: 0.546708
  type: 'test'
  ...
# Subtest: attachment processing rejects path-like draft IDs and still cleans its temp file
ok 5 - attachment processing rejects path-like draft IDs and still cleans its temp file
  ---
  duration_ms: 1.850826
  type: 'test'
  ...
# [2026-08-29 15:06:05.693 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/003-attachmentUploadCleanup.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:05.708 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..5
# tests 5
# suites 0
# pass 5
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2054.715158

[4/311] packages/api/test/authGithubTokens.test.ts
TAP version 13
# Refreshing GitHub token for user octocat (force=true)
# Successfully refreshed GitHub token for user octocat
# Refreshing GitHub token for user octocat (force=true)
# GitHub token refresh failed with status 503
# Refreshing GitHub token for user octocat (force=true)
# Subtest: isGitHubTokenExpired handles missing, future, exact, and past expiry values
ok 1 - isGitHubTokenExpired handles missing, future, exact, and past expiry values
  ---
  duration_ms: 2.407608
  type: 'test'
  ...
# Subtest: ensureAuthenticated refreshes an expired GitHub token before continuing
ok 2 - ensureAuthenticated refreshes an expired GitHub token before continuing
  ---
  duration_ms: 5.724901
  type: 'test'
  ...
# Subtest: ensureAuthenticated reports a temporary error when refresh fails recoverably
ok 3 - ensureAuthenticated reports a temporary error when refresh fails recoverably
  ---
  duration_ms: 1.654795
  type: 'test'
  ...
# Successfully refreshed GitHub token for user octocat
# Saved refreshed GitHub token for concurrent request by user octocat
# Refreshing GitHub token for user octocat (force=true)
# GitHub token refresh response missing access_token
# Refreshing GitHub token for user octocat (force=true)
# GitHub token refresh error: bad_refresh_token - The refresh token is invalid.
# Marked GitHub OAuth session for user octocat as requiring re-authentication (bad_refresh_token)
# GitHub token expired or revoked, attempting token refresh
# Refreshing GitHub token for user octocat (force=true)
# Successfully refreshed GitHub token for user octocat
# Token refresh successful, client should retry
# Subtest: ensureAuthenticated coalesces concurrent expired-token refreshes for one session
ok 4 - ensureAuthenticated coalesces concurrent expired-token refreshes for one session
  ---
  duration_ms: 11.000237
  type: 'test'
  ...
# Subtest: ensureAuthenticated rejects an expired GitHub token with no refresh token
ok 5 - ensureAuthenticated rejects an expired GitHub token with no refresh token
  ---
  duration_ms: 0.684311
  type: 'test'
  ...
# Subtest: ensureAuthenticated reports a temporary error when refresh omits an access token
ok 6 - ensureAuthenticated reports a temporary error when refresh omits an access token
  ---
  duration_ms: 0.970765
  type: 'test'
  ...
# Subtest: ensureAuthenticated clears the session after an unrecoverable refresh error
ok 7 - ensureAuthenticated clears the session after an unrecoverable refresh error
  ---
  duration_ms: 1.080607
  type: 'test'
  ...
# Subtest: GitHub route auth error emits TOKEN_REFRESHED after a successful refresh
ok 8 - GitHub route auth error emits TOKEN_REFRESHED after a successful refresh
  ---
  duration_ms: 1.024244
  type: 'test'
  ...
# [2026-08-29 15:06:08.351 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/004-authGithubTokens.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:08.370 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..8
# tests 8
# suites 0
# pass 8
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2505.474176

[5/311] packages/api/test/authRedirect.test.ts
TAP version 13
# Subtest: auth redirect allowlist treats FRONTEND_URL as exact host only
ok 1 - auth redirect allowlist treats FRONTEND_URL as exact host only
  ---
  duration_ms: 48.830015
  type: 'test'
  ...
# Subtest: proxy mode auth redirect fallback returns the hosted UI origin
ok 2 - proxy mode auth redirect fallback returns the hosted UI origin
  ---
  duration_ms: 10.362565
  type: 'test'
  ...
# Subtest: auth redirect allowlist permits subdomains only for explicit wildcard-style hosts
ok 3 - auth redirect allowlist permits subdomains only for explicit wildcard-style hosts
  ---
  duration_ms: 6.399117
  type: 'test'
  ...
# Subtest: auth redirect allowlist permits leading-dot COOKIE_DOMAIN subdomains
ok 4 - auth redirect allowlist permits leading-dot COOKIE_DOMAIN subdomains
  ---
  duration_ms: 5.615699
  type: 'test'
  ...
# Subtest: auth redirect allowlist permits exact additional hosts without permitting their subdomains
ok 5 - auth redirect allowlist permits exact additional hosts without permitting their subdomains
  ---
  duration_ms: 13.571287
  type: 'test'
  ...
# Subtest: auth redirect allowlist permits wildcard entries with protocol prefixes
ok 6 - auth redirect allowlist permits wildcard entries with protocol prefixes
  ---
  duration_ms: 7.917721
  type: 'test'
  ...
# Subtest: auth redirect allowlist rejects invalid URLs and non-http protocols
ok 7 - auth redirect allowlist rejects invalid URLs and non-http protocols
  ---
  duration_ms: 8.412353
  type: 'test'
  ...
# Subtest: auth redirect allowlist only permits cleartext HTTP for localhost
ok 8 - auth redirect allowlist only permits cleartext HTTP for localhost
  ---
  duration_ms: 7.303965
  type: 'test'
  ...
# Subtest: auth redirect allowlist permits configured local IP literals
ok 9 - auth redirect allowlist permits configured local IP literals
  ---
  duration_ms: 6.692992
  type: 'test'
  ...
# Subtest: auth redirect allowlist ignores malformed additional host entries
ok 10 - auth redirect allowlist ignores malformed additional host entries
  ---
  duration_ms: 6.417284
  type: 'test'
  ...
# [2026-08-29 15:06:10.982 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/005-authRedirect.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:11.097 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..10
# tests 10
# suites 0
# pass 10
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2534.08675

[6/311] packages/api/test/configAgentValidation.antigravity.test.ts
TAP version 13
# Subtest: agent config validation accepts antigravity and rejects gemini for new configs
ok 1 - agent config validation accepts antigravity and rejects gemini for new configs
  ---
  duration_ms: 1533.553952
  type: 'test'
  ...
# [2026-08-29 15:06:13.233 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/006-configAgentValidation.antigravity.test.ts/propr.test.sqlite"
#     environment: "test"
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2101.571068

[7/311] packages/api/test/configReloadSubscription.test.ts
TAP version 13
# Subtest: API config subscription serializes the startup reload with settings updates
ok 1 - API config subscription serializes the startup reload with settings updates
  ---
  duration_ms: 4.503326
  type: 'test'
  ...
# Subtest: API config subscription reloads repository updates
ok 2 - API config subscription reloads repository updates
  ---
  duration_ms: 0.403105
  type: 'test'
  ...
# Subtest: API config subscription ignores unrelated and malformed events
ok 3 - API config subscription ignores unrelated and malformed events
  ---
  duration_ms: 0.282037
  type: 'test'
  ...
# Subtest: a failed API settings reload does not block the next notification
ok 4 - a failed API settings reload does not block the next notification
  ---
  duration_ms: 0.336387
  type: 'test'
  ...
1..4
# tests 4
# suites 0
# pass 4
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 240.227742

[8/311] packages/api/test/configRoutesIndexingSummarization.test.ts
TAP version 13
# [2026-08-29 15:06:15.845 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/008-configRoutesIndexingSummarization.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:15.875 +0000] �[32mINFO�[39m: �[36mRunning database migrations...�[39m
# Subtest: postSummarizationSettings trims model-specific aliases before saving
ok 1 - postSummarizationSettings trims model-specific aliases before saving
  ---
  duration_ms: 1837.935722
  type: 'test'
  ...
# Subtest: postSummarizationSettings rejects enabled summarization without a primary alias
ok 2 - postSummarizationSettings rejects enabled summarization without a primary alias
  ---
  duration_ms: 4.235181
  type: 'test'
  ...
# [2026-08-29 15:06:16.128 +0000] �[32mINFO�[39m: �[36mDatabase migrations completed successfully�[39m
# [2026-08-29 15:06:16.130 +0000] �[32mINFO�[39m: �[36mSuccessfully loaded agents configuration�[39m
#     agentCount: 2
# [2026-08-29 15:06:16.130 +0000] �[32mINFO�[39m: �[36mSuccessfully loaded summarization settings�[39m
#     summarization: {
#       "enabled": false,
#       "agent_alias": "",
#       "fallback_agent_alias": "",
#       "custom_prompt": ""
#     }
# [2026-08-29 15:06:16.132 +0000] �[32mINFO�[39m: �[36mSuccessfully saved summarization settings�[39m
#     summarization: {
#       "enabled": true,
#       "agent_alias": "codex:gpt-5.5",
#       "fallback_agent_alias": "fallback:gpt-5.4",
#       "custom_prompt": ""
#     }
# [2026-08-29 15:06:16.132 +0000] �[32mINFO�[39m: �[36mSuccessfully loaded summarization settings�[39m
#     summarization: {
#       "enabled": true,
#       "agent_alias": "codex:gpt-5.5",
#       "fallback_agent_alias": "fallback:gpt-5.4",
#       "custom_prompt": ""
#     }
# [2026-08-29 15:06:16.144 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..2
# tests 2
# suites 0
# pass 2
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2268.754054

[9/311] packages/api/test/connectAuth.test.ts
TAP version 13
# Subtest: relay tunnel mode uses Connect without local OAuth credentials
ok 1 - relay tunnel mode uses Connect without local OAuth credentials
  ---
  duration_ms: 1.215918
  type: 'test'
  ...
# Subtest: relay tunnel mode preserves Connect for operator-supplied service endpoints
ok 2 - relay tunnel mode preserves Connect for operator-supplied service endpoints
  ---
  duration_ms: 0.243029
  type: 'test'
  ...
# Subtest: local relay mode uses Connect without a per-instance OAuth App
ok 3 - local relay mode uses Connect without a per-instance OAuth App
  ---
  duration_ms: 0.271321
  type: 'test'
  ...
# Subtest: off-tunnel relay inference rejects callbacks outside the exact loopback allowlist
ok 4 - off-tunnel relay inference rejects callbacks outside the exact loopback allowlist
  ---
  duration_ms: 0.322247
  type: 'test'
  ...
# Subtest: off-tunnel custom relay enrollment does not infer hosted Connect auth
ok 5 - off-tunnel custom relay enrollment does not infer hosted Connect auth
  ---
  duration_ms: 0.170091
  type: 'test'
  ...
# Subtest: literal example OAuth placeholders do not enable GitHub web auth
ok 6 - literal example OAuth placeholders do not enable GitHub web auth
  ---
  duration_ms: 0.148329
  type: 'test'
  ...
# Subtest: explicit custom GitHub web auth remains supported
ok 7 - explicit custom GitHub web auth remains supported
  ---
  duration_ms: 0.177392
  type: 'test'
  ...
# Subtest: explicit custom GitHub web auth wins over relay inference off-tunnel
ok 8 - explicit custom GitHub web auth wins over relay inference off-tunnel
  ---
  duration_ms: 0.178264
  type: 'test'
  ...
# Subtest: Connect authorization URL carries the exact callback and CSRF state
ok 9 - Connect authorization URL carries the exact callback and CSRF state
  ---
  duration_ms: 0.820473
  type: 'test'
  ...
# Subtest: redeems a Connect code server-to-server without exposing the relay token in the body
ok 10 - redeems a Connect code server-to-server without exposing the relay token in the body
  ---
  duration_ms: 30.546537
  type: 'test'
  ...
# Subtest: binds the Connect identity username to the validated token owner
ok 11 - binds the Connect identity username to the validated token owner
  ---
  duration_ms: 1.037524
  type: 'test'
  ...
1..11
# tests 11
# suites 0
# pass 11
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 307.908567

[10/311] packages/api/test/connectAuthCallback.test.ts
TAP version 13
# [2026-08-29 15:06:19.111 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/010-connectAuthCallback.test.ts/propr.test.sqlite"
#     environment: "test"
# Subtest: Connect login preserves a validated redirect_to across Passport session regeneration
ok 1 - Connect login preserves a validated redirect_to across Passport session regeneration
  ---
  duration_ms: 3042.416506
  type: 'test'
  ...
# [2026-08-29 15:06:22.149 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 5544.405875

[11/311] packages/api/test/corsValidation.test.ts
TAP version 13
# Subtest: CORS allows the hosted UI origin under proxy mode
ok 1 - CORS allows the hosted UI origin under proxy mode
  ---
  duration_ms: 0.967691
  type: 'test'
  ...
# Subtest: CORS rejects unrelated origins under proxy mode
ok 2 - CORS rejects unrelated origins under proxy mode
  ---
  duration_ms: 0.232254
  type: 'test'
  ...
# Subtest: CORS allows requests with no origin
ok 3 - CORS allows requests with no origin
  ---
  duration_ms: 0.131535
  type: 'test'
  ...
# Subtest: CORS allows localhost for development
ok 4 - CORS allows localhost for development
  ---
  duration_ms: 0.140278
  type: 'test'
  ...
# Subtest: CORS rejects non-http(s) localhost schemes
ok 5 - CORS rejects non-http(s) localhost schemes
  ---
  duration_ms: 0.25664
  type: 'test'
  ...
# Subtest: CORS allows COOKIE_DOMAIN subdomains for preview environments
ok 6 - CORS allows COOKIE_DOMAIN subdomains for preview environments
  ---
  duration_ms: 0.207867
  type: 'test'
  ...
# Subtest: CORS preserves http COOKIE_DOMAIN preview compatibility
ok 7 - CORS preserves http COOKIE_DOMAIN preview compatibility
  ---
  duration_ms: 0.208228
  type: 'test'
  ...
# Subtest: CORS validator factory throws on an invalid FRONTEND_URL
ok 8 - CORS validator factory throws on an invalid FRONTEND_URL
  ---
  duration_ms: 0.305692
  type: 'test'
  ...
# Subtest: Express CORS boundary is sanitized in development mode
ok 9 - Express CORS boundary is sanitized in development mode
  ---
  duration_ms: 81.544227
  type: 'test'
  ...
# Subtest: Express CORS boundary is sanitized in production mode
ok 10 - Express CORS boundary is sanitized in production mode
  ---
  duration_ms: 27.583917
  type: 'test'
  ...
1..10
# tests 10
# suites 0
# pass 10
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 487.732842

[12/311] packages/api/test/demoMode.test.ts
TAP version 13
# Subtest: demoModeReadOnlyMiddleware rejects mutating requests in demo mode
ok 1 - demoModeReadOnlyMiddleware rejects mutating requests in demo mode
  ---
  duration_ms: 6.426624
  type: 'test'
  ...
# Subtest: demoModeReadOnlyMiddleware blocks auth metadata mutations
ok 2 - demoModeReadOnlyMiddleware blocks auth metadata mutations
  ---
  duration_ms: 1.955592
  type: 'test'
  ...
# Subtest: isDemoMode accepts common truthy environment values
ok 3 - isDemoMode accepts common truthy environment values
  ---
  duration_ms: 1.041931
  type: 'test'
  ...
# Subtest: configured demo mode keeps auth and middleware on the same startup value
ok 4 - configured demo mode keeps auth and middleware on the same startup value
  ---
  duration_ms: 1.378649
  type: 'test'
  ...
# Subtest: demo Redis facade covers read-only route Redis usage
ok 5 - demo Redis facade covers read-only route Redis usage
  ---
  duration_ms: 3.521368
  type: 'test'
  ...
# Subtest: demo Express GET routes work with the in-memory Redis facade
ok 6 - demo Express GET routes work with the in-memory Redis facade
  ---
  duration_ms: 59.620911
  type: 'test'
  ...
# Subtest: ensureAuthenticated attaches the synthetic demo user
ok 7 - ensureAuthenticated attaches the synthetic demo user
  ---
  duration_ms: 1.154517
  type: 'test'
  ...
# Subtest: ensureAuthenticated ignores bearer auth and attaches the synthetic demo user in demo mode
ok 8 - ensureAuthenticated ignores bearer auth and attaches the synthetic demo user in demo mode
  ---
  duration_ms: 0.977846
  type: 'test'
  ...
# Subtest: demo repository metadata resolves enabled configured repositories
ok 9 - demo repository metadata resolves enabled configured repositories
  ---
  duration_ms: 9.569873
  type: 'test'
  ...
# Subtest: repository config branch validation documents ProPR-supported branch names
ok 10 - repository config branch validation documents ProPR-supported branch names
  ---
  duration_ms: 2.386349
  type: 'test'
  ...
# [2026-08-29 15:06:25.490 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/012-demoMode.test.ts/propr.test.sqlite"
#     environment: "test"
# Subtest: /api/github/repos returns configured and persisted repositories in demo mode
ok 11 - /api/github/repos returns configured and persisted repositories in demo mode
  ---
  duration_ms: 264.604424
  type: 'test'
  ...
# Subtest: demo repository metadata resolves persisted repositories without configured allowlists
ok 12 - demo repository metadata resolves persisted repositories without configured allowlists
  ---
  duration_ms: 10.211762
  type: 'test'
  ...
# Subtest: demo repository metadata ignores malformed database repository names
ok 13 - demo repository metadata ignores malformed database repository names
  ---
  duration_ms: 1.53483
  type: 'test'
  ...
# [2026-08-29 15:06:25.834 +0000] �[32mINFO�[39m: �[36mSuccessfully saved monitored repositories�[39m
#     repos: [
#       {
#         "id": "1",
#         "name": "integry/propr",
#         "enabled": true
#       },
#       {
#         "id": "2",
#         "name": "integry/private",
#         "enabled": true
#       },
#       {
#         "id": "3",
#         "name": "integry/disabled",
#         "enabled": false
#       }
#     ]
# [2026-08-29 15:06:25.836 +0000] �[32mINFO�[39m: �[36mSuccessfully loaded all monitored repositories�[39m
#     total_repos: 3
# [2026-08-29 15:06:25.847 +0000] �[32mINFO�[39m: �[36mSuccessfully loaded all monitored repositories�[39m
#     total_repos: 0
# Subtest: planner demo reads use the curated database without owner or repository allowlists
ok 14 - planner demo reads use the curated database without owner or repository allowlists
  ---
  duration_ms: 18.180126
  type: 'test'
  ...
# [2026-08-29 15:06:25.865 +0000] �[32mINFO�[39m: �[36mSuccessfully saved monitored repositories�[39m
#     repos: [
#       {
#         "id": "1",
#         "name": "integry/propr",
#         "enabled": true
#       },
#       {
#         "id": "2",
#         "name": "integry/private",
#         "enabled": true
#       }
#     ]
# Subtest: repo todo demo reads use the curated database without owner filters
ok 15 - repo todo demo reads use the curated database without owner filters
  ---
  duration_ms: 7.698775
  type: 'test'
  ...
# Subtest: auth demo-mode metadata endpoint reports startup environment value
ok 16 - auth demo-mode metadata endpoint reports startup environment value
  ---
  duration_ms: 8.279784
  type: 'test'
  ...
1..16
# tests 16
# suites 0
# pass 16
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2724.213298

[13/311] packages/api/test/desktopAuth.test.ts
TAP version 13
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_aBVw7vnqW0aC5WDjpQ7C9g',
#   tokenId: undefined,
#   clientName: 'Work Laptop'
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_ZyaRr53YTub7xayiF0UGUA',
#   tokenId: undefined,
#   clientName: 'Windows desktop'
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_qhuMv2--P2zmt-jywLlN0Q',
#   tokenId: undefined,
#   clientName: 'MacBook Pro'
# }
# [desktop-auth] {
#   action: 'pairing_approved',
#   actorUserId: '101',
#   pairingId: 'dpr_qhuMv2--P2zmt-jywLlN0Q',
#   tokenId: undefined,
#   clientName: 'MacBook Pro'
# }
# [desktop-auth] {
#   action: 'token_issued',
#   actorUserId: '101',
#   pairingId: 'dpr_qhuMv2--P2zmt-jywLlN0Q',
#   tokenId: '24e4fb29-fd35-4be1-b155-9180337adfbe',
#   clientName: 'MacBook Pro'
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_xhWSd2tKomn9iDOlmz5LWA',
#   tokenId: undefined,
#   clientName: 'Linux workstation'
# }
# [desktop-auth] {
#   action: 'pairing_approved',
#   actorUserId: '101',
#   pairingId: 'dpr_xhWSd2tKomn9iDOlmz5LWA',
#   tokenId: undefined,
#   clientName: 'Linux workstation'
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_ofapkNdQLxenlyn4QpBTUQ',
#   tokenId: undefined,
#   clientName: 'Old laptop'
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_7NnxKyOZ1kjj6Xt-YuIr1w',
#   tokenId: undefined,
#   clientName: 'Desktop app'
# }
# [desktop-auth] {
#   action: 'pairing_approved',
#   actorUserId: '101',
#   pairingId: 'dpr_7NnxKyOZ1kjj6Xt-YuIr1w',
#   tokenId: undefined,
#   clientName: 'Desktop app'
# }
# [desktop-auth] {
#   action: 'token_issued',
#   actorUserId: '101',
#   pairingId: 'dpr_7NnxKyOZ1kjj6Xt-YuIr1w',
#   tokenId: '49900d4d-19cc-44f4-b7c7-6d8e55b5f1f4',
#   clientName: 'Desktop app'
# }
# [desktop-auth] {
#   action: 'token_revoked',
#   actorUserId: '101',
#   pairingId: undefined,
#   tokenId: '49900d4d-19cc-44f4-b7c7-6d8e55b5f1f4',
#   clientName: undefined
# }
# [desktop-auth] {
#   action: 'pairing_started',
#   actorUserId: undefined,
#   pairingId: 'dpr_PX25uD8A2JP-ccZ-jmnI8w',
#   tokenId: undefined,
#   clientName: 'Desktop app'
# }
# [desktop-auth] {
#   action: 'pairing_approved',
#   actorUserId: '101',
#   pairingId: 'dpr_PX25uD8A2JP-ccZ-jmnI8w',
#   tokenId: undefined,
#   clientName: 'Desktop app'
# }
# [desktop-auth] {
#   action: 'token_issued',
#   actorUserId: '101',
#   pairingId: 'dpr_PX25uD8A2JP-ccZ-jmnI8w',
#   tokenId: '827133dd-b504-444a-b796-5ced4deb2574',
#   clientName: 'Desktop app'
# }
# Subtest: desktop browser pairing
    # Subtest: stores only a device-secret hash and builds a fixed trusted approval URL
    ok 1 - stores only a device-secret hash and builds a fixed trusted approval URL
      ---
      duration_ms: 16.787546
      type: 'test'
      ...
    # Subtest: uses the configured API browser entry and preserves only a managed hosted tunnel selector
    ok 2 - uses the configured API browser entry and preserves only a managed hosted tunnel selector
      ---
      duration_ms: 4.946505
      type: 'test'
      ...
    # Subtest: issues an opaque token once, resolves its owner, and never stores plaintext credentials
    ok 3 - issues an opaque token once, resolves its owner, and never stores plaintext credentials
      ---
      duration_ms: 19.102069
      type: 'test'
      ...
    # Subtest: rejects the wrong secret without revealing pairing state
    ok 4 - rejects the wrong secret without revealing pairing state
      ---
      duration_ms: 6.444
      type: 'test'
      ...
    # Subtest: expires unapproved pairings and cleans retained expired records
    ok 5 - expires unapproved pairings and cleans retained expired records
      ---
      duration_ms: 6.73504
      type: 'test'
      ...
    # Subtest: rejects unsafe names and non-HTTPS approval origins
    ok 6 - rejects unsafe names and non-HTTPS approval origins
      ---
      duration_ms: 4.215765
      type: 'test'
      ...
    1..6
ok 1 - desktop browser pairing
  ---
  duration_ms: 59.485129
  type: 'suite'
  ...
# Subtest: instance token ownership and revocation
    # Subtest: lists safe metadata only and limits revocation to the owner
    ok 1 - lists safe metadata only and limits revocation to the owner
      ---
      duration_ms: 12.971423
      type: 'test'
      ...
    # Subtest: honors optional token expiry
    ok 2 - honors optional token expiry
      ---
      duration_ms: 7.252035
      type: 'test'
      ...
    # Subtest: REST authentication accepts instance tokens while optional GitHub bearer auth is disabled
    ok 3 - REST authentication accepts instance tokens while optional GitHub bearer auth is disabled
      ---
      duration_ms: 3.856923
      type: 'test'
      ...
    1..3
ok 2 - instance token ownership and revocation
  ---
  duration_ms: 24.596334
  type: 'suite'
  ...
# Subtest: pairing approval request protection
    # Subtest: accepts only the exact HTTPS frontend origin
    ok 1 - accepts only the exact HTTPS frontend origin
      ---
      duration_ms: 2.487949
      type: 'test'
      ...
    # Subtest: requires a browser session even when another authentication method supplied the user
    ok 2 - requires a browser session even when another authentication method supplied the user
      ---
      duration_ms: 2.471044
      type: 'test'
      ...
    1..2
ok 3 - pairing approval request protection
  ---
  duration_ms: 5.100653
  type: 'suite'
  ...
# [2026-08-29 15:06:28.197 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/013-desktopAuth.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:28.281 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..3
# tests 11
# suites 3
# pass 11
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2859.501762

[14/311] packages/api/test/dockerCommandSafety.test.ts
TAP version 13
# Subtest: accepts Docker IDs and ProPR-generated container names
ok 1 - accepts Docker IDs and ProPR-generated container names
  ---
  duration_ms: 0.897517
  type: 'test'
  ...
# Subtest: rejects container references that could be parsed as options or shell syntax
ok 2 - rejects container references that could be parsed as options or shell syntax
  ---
  duration_ms: 0.151704
  type: 'test'
  ...
# Subtest: production subprocess call sites do not invoke a command shell
ok 3 - production subprocess call sites do not invoke a command shell
  ---
  duration_ms: 72.294322
  type: 'test'
  ...
# Subtest: no-shell guard rejects aliases and enabled shell options
ok 4 - no-shell guard rejects aliases and enabled shell options
  ---
  duration_ms: 3.524229
  type: 'test'
  ...
1..4
# tests 4
# suites 0
# pass 4
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 964.668129

[15/311] packages/api/test/instanceAuthorization.test.ts
TAP version 13
# Subtest: instance authorization
    # Subtest: defaults unassigned authenticated users to members on a new installation
    ok 1 - defaults unassigned authenticated users to members on a new installation
      ---
      duration_ms: 10.951317
      type: 'test'
      ...
    # Subtest: refuses startup until a bootstrap or durable administrator exists
    ok 2 - refuses startup until a bootstrap or durable administrator exists
      ---
      duration_ms: 4.892852
      type: 'test'
      ...
    # Subtest: grants full admin permissions to PROPR_ADMIN_USERS
    ok 3 - grants full admin permissions to PROPR_ADMIN_USERS
      ---
      duration_ms: 2.556088
      type: 'test'
      ...
    # Subtest: resolves durable roles by numeric GitHub ID after a username change
    ok 4 - resolves durable roles by numeric GitHub ID after a username change
      ---
      duration_ms: 2.684377
      type: 'test'
      ...
    # Subtest: resolves demo users without installation permissions
    ok 5 - resolves demo users without installation permissions
      ---
      duration_ms: 2.127765
      type: 'test'
      ...
    # Subtest: permission middleware rejects members with a stable error code
    ok 6 - permission middleware rejects members with a stable error code
      ---
      duration_ms: 2.093905
      type: 'test'
      ...
    # Subtest: current-user responses expose capabilities without OAuth credentials
    ok 7 - current-user responses expose capabilities without OAuth credentials
      ---
      duration_ms: 2.508027
      type: 'test'
      ...
    1..7
ok 1 - instance authorization
  ---
  duration_ms: 29.054944
  type: 'suite'
  ...
# Subtest: instance member service
    # Subtest: does not let an unassigned user claim the initial administrator role
    ok 1 - does not let an unassigned user claim the initial administrator role
      ---
      duration_ms: 3.296973
      type: 'test'
      ...
    # Subtest: stores a bootstrap administrator against their numeric GitHub ID
    ok 2 - stores a bootstrap administrator against their numeric GitHub ID
      ---
      duration_ms: 5.926179
      type: 'test'
      ...
    # Subtest: adds explicit members and writes an audit entry
    ok 3 - adds explicit members and writes an audit entry
      ---
      duration_ms: 9.281359
      type: 'test'
      ...
    # Subtest: keeps environment authority separate from durable role assignments
    ok 4 - keeps environment authority separate from durable role assignments
      ---
      duration_ms: 2.606813
      type: 'test'
      ...
    # Subtest: prevents removing the last durable administrator
    ok 5 - prevents removing the last durable administrator
      ---
      duration_ms: 3.972752
      type: 'test'
      ...
    # Subtest: allows role changes once another administrator exists
    ok 6 - allows role changes once another administrator exists
      ---
      duration_ms: 4.731803
      type: 'test'
      ...
    1..6
ok 2 - instance member service
  ---
  duration_ms: 30.26971
  type: 'suite'
  ...
# Subtest: instance catalog
    # Subtest: returns operational agent and repository fields without installation internals
    ok 1 - returns operational agent and repository fields without installation internals
      ---
      duration_ms: 2.176427
      type: 'test'
      ...
    # Subtest: projects indexing status only for enabled repository and branch entries
    ok 2 - projects indexing status only for enabled repository and branch entries
      ---
      duration_ms: 1.722897
      type: 'test'
      ...
    1..2
ok 3 - instance catalog
  ---
  duration_ms: 3.997268
  type: 'suite'
  ...
# Subtest: instance admin routes
    # Subtest: resolves a GitHub username and creates one durable member assignment
    ok 1 - resolves a GitHub username and creates one durable member assignment
      ---
      duration_ms: 2.791336
      type: 'test'
      ...
    # Subtest: rejects a non-numeric audit limit with a 400
    ok 2 - rejects a non-numeric audit limit with a 400
      ---
      duration_ms: 1.384306
      type: 'test'
      ...
    # Subtest: rejects GitHub usernames with trailing or consecutive hyphens
    ok 3 - rejects GitHub usernames with trailing or consecutive hyphens
      ---
      duration_ms: 1.477934
      type: 'test'
      ...
    1..3
ok 4 - instance admin routes
  ---
  duration_ms: 5.773213
  type: 'suite'
  ...
# [2026-08-29 15:06:31.978 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/015-instanceAuthorization.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:32.042 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..4
# tests 18
# suites 4
# pass 18
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2198.055259

[16/311] packages/api/test/listenAddress.test.ts
TAP version 13
# Subtest: direct API execution binds to loopback by default
ok 1 - direct API execution binds to loopback by default
  ---
  duration_ms: 0.772201
  type: 'test'
  ...
# Subtest: containerized API execution remains reachable through its published port
ok 2 - containerized API execution remains reachable through its published port
  ---
  duration_ms: 0.12829
  type: 'test'
  ...
# Subtest: an explicit API listen host overrides environment defaults
ok 3 - an explicit API listen host overrides environment defaults
  ---
  duration_ms: 0.11499
  type: 'test'
  ...
1..3
# tests 3
# suites 0
# pass 3
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 254.799402

[17/311] packages/api/test/liveDetailsAntigravity.test.ts
TAP version 13
# Failed to read GitHub App private key: ENOENT: no such file or directory, open '/tmp/missing-key.pem'
# Ensure GH_PRIVATE_KEY_PATH is set correctly in your .env file and points to a valid private key file.
# Subtest: stored output detection recognizes Antigravity stream JSON
ok 1 - stored output detection recognizes Antigravity stream JSON
  ---
  duration_ms: 2.29416
  type: 'test'
  ...
# Subtest: stored output detection keeps Codex message JSONL classified as Codex
ok 2 - stored output detection keeps Codex message JSONL classified as Codex
  ---
  duration_ms: 1.443794
  type: 'test'
  ...
# Subtest: stored output detection keeps Codex result JSONL classified as Codex
ok 3 - stored output detection keeps Codex result JSONL classified as Codex
  ---
  duration_ms: 0.881053
  type: 'test'
  ...
# Subtest: stored output detection keeps Codex tool result JSONL classified as Codex
ok 4 - stored output detection keeps Codex tool result JSONL classified as Codex
  ---
  duration_ms: 0.198093
  type: 'test'
  ...
# Subtest: stored output detection does not treat generic init JSONL as Antigravity
ok 5 - stored output detection does not treat generic init JSONL as Antigravity
  ---
  duration_ms: 0.308796
  type: 'test'
  ...
# Subtest: stored output detection recognizes Antigravity JSONL from result stats when init is missing
ok 6 - stored output detection recognizes Antigravity JSONL from result stats when init is missing
  ---
  duration_ms: 0.341134
  type: 'test'
  ...
# Subtest: stored output detection keeps generic result token stats classified as Codex
ok 7 - stored output detection keeps generic result token stats classified as Codex
  ---
  duration_ms: 0.204643
  type: 'test'
  ...
# Subtest: stored output detection recognizes truncated Antigravity result JSON
ok 8 - stored output detection recognizes truncated Antigravity result JSON
  ---
  duration_ms: 0.155029
  type: 'test'
  ...
# Subtest: stored output detection recognizes Antigravity message JSON with model metadata
ok 9 - stored output detection recognizes Antigravity message JSON with model metadata
  ---
  duration_ms: 0.374603
  type: 'test'
  ...
# Subtest: stored output parsing renders only Antigravity analysis events through live details
ok 10 - stored output parsing renders only Antigravity analysis events through live details
  ---
  duration_ms: 66.340858
  type: 'test'
  ...
# Subtest: Antigravity 1.1.12 stream text remains visible through live details
ok 11 - Antigravity 1.1.12 stream text remains visible through live details
  ---
  duration_ms: 1.757948
  type: 'test'
  ...
# Subtest: stored output detection and live-details rendering consume Antigravity stream arrays
ok 12 - stored output detection and live-details rendering consume Antigravity stream arrays
  ---
  duration_ms: 1.341212
  type: 'test'
  ...
# Subtest: Antigravity cache-only stream usage remains visible through live details
ok 13 - Antigravity cache-only stream usage remains visible through live details
  ---
  duration_ms: 0.870857
  type: 'test'
  ...
# Subtest: stored output parsing filters Antigravity transcript tool items
ok 14 - stored output parsing filters Antigravity transcript tool items
  ---
  duration_ms: 1.026227
  type: 'test'
  ...
# Subtest: Claude-format Antigravity conversation files render only planner analysis
ok 15 - Claude-format Antigravity conversation files render only planner analysis
  ---
  duration_ms: 1.363045
  type: 'test'
  ...
# Subtest: execution detail fallback filters Antigravity transcript tool rows
ok 16 - execution detail fallback filters Antigravity transcript tool rows
  ---
  duration_ms: 0.765322
  type: 'test'
  ...
# [2026-08-29 15:06:34.700 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/017-liveDetailsAntigravity.test.ts/propr.test.sqlite"
#     environment: "test"
1..16
# tests 16
# suites 0
# pass 16
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2123.613442

[18/311] packages/api/test/liveDetailsCodexDbFallback.test.ts
TAP version 13
# [live-details] jobId: integry-propr-1915-codex, taskId: integry-propr-1915-codex
# [live-details] Trying Redis fallback
# [live-details] stateKey: worker:state:integry-propr-1915-codex, hasData: false
# [live-details] No state data found in Redis
# [live-details] Fetching sessionId from SQLite for taskId: integry-propr-1915-codex
# [live-details] Found sessionId in SQLite: codex-db-session
# [live-details] Using sessionId: codex-db-session
# Subtest: Codex database lifecycle fallback has exact canonical event parity
ok 1 - Codex database lifecycle fallback has exact canonical event parity
  ---
  duration_ms: 4.408476
  type: 'test'
  ...
# Subtest: Codex command lifecycle pairs starts and completions and recovers an unmatched completion
ok 2 - Codex command lifecycle pairs starts and completions and recovers an unmatched completion
  ---
  duration_ms: 0.363658
  type: 'test'
  ...
# Subtest: Codex database fallback retains row content for minimal error metadata
ok 3 - Codex database fallback retains row content for minimal error metadata
  ---
  duration_ms: 0.172364
  type: 'test'
  ...
# Subtest: Codex database fallback retains row content and error flag for minimal tool-result metadata
ok 4 - Codex database fallback retains row content and error flag for minimal tool-result metadata
  ---
  duration_ms: 0.140738
  type: 'test'
  ...
# Subtest: Codex database fallback ignores envelopes while retaining text, errors, and todos
ok 5 - Codex database fallback ignores envelopes while retaining text, errors, and todos
  ---
  duration_ms: 0.451087
  type: 'test'
  ...
# [live-details] Checking Claude conversation path: not found
# [live-details] Claude conversation file not found, trying active Redis output
# [live-details] Claude conversation file not found, trying stored execution output fallback
# [live-details] No stored execution logs found in Redis for session fallback
# [live-details] Stored execution output fallback unavailable, trying database fallback
# [live-details] jobId: integry-propr-1915-codex, taskId: integry-propr-1915-codex
# [live-details] Trying Redis fallback
# [live-details] stateKey: worker:state:integry-propr-1915-codex, hasData: false
# [live-details] No state data found in Redis
# [live-details] Fetching sessionId from SQLite for taskId: integry-propr-1915-codex
# [live-details] Found sessionId in SQLite: codex-db-session
# [live-details] Using sessionId: codex-db-session
# [live-details] Checking Claude conversation path: not found
# [live-details] Claude conversation file not found, trying active Redis output
# [live-details] Claude conversation file not found, trying stored execution output fallback
# [live-details] No stored execution logs found in Redis for session fallback
# [live-details] Stored execution output fallback unavailable, trying database fallback
# Subtest: live-details database fallback preserves token usage and stable event IDs
ok 6 - live-details database fallback preserves token usage and stable event IDs
  ---
  duration_ms: 19.199758
  type: 'test'
  ...
# [2026-08-29 15:06:36.928 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/018-liveDetailsCodexDbFallback.test.ts/propr.test.sqlite"
#     environment: "test"
1..6
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 1901.137144

[19/311] packages/api/test/liveDetailsOpenCodeParser.test.ts
TAP version 13
# Subtest: detectStoredOutputFormat keeps Codex message streams with session_id as codex
ok 1 - detectStoredOutputFormat keeps Codex message streams with session_id as codex
  ---
  duration_ms: 1516.3591
  type: 'test'
  ...
# Subtest: detectStoredOutputFormat does not classify bare conversation_id JSON as Claude
ok 2 - detectStoredOutputFormat does not classify bare conversation_id JSON as Claude
  ---
  duration_ms: 5.822686
  type: 'test'
  ...
# Subtest: detectStoredOutputFormat keeps Claude-shaped conversation_id JSON as Claude
ok 3 - detectStoredOutputFormat keeps Claude-shaped conversation_id JSON as Claude
  ---
  duration_ms: 1.391887
  type: 'test'
  ...
# Subtest: parseOpenCodeOutputToConversationResult separates structured assistant text parts
ok 4 - parseOpenCodeOutputToConversationResult separates structured assistant text parts
  ---
  duration_ms: 17.769078
  type: 'test'
  ...
# Subtest: detectStoredOutputFormat recognizes whole-document pretty OpenCode JSON
ok 5 - detectStoredOutputFormat recognizes whole-document pretty OpenCode JSON
  ---
  duration_ms: 1.698861
  type: 'test'
  ...
# Subtest: detectStoredOutputFormat recognizes OpenCode assistant parts without session identifiers
ok 6 - detectStoredOutputFormat recognizes OpenCode assistant parts without session identifiers
  ---
  duration_ms: 0.837598
  type: 'test'
  ...
# Subtest: detectStoredOutputFormat recognizes whole-document pretty Claude JSON arrays
ok 7 - detectStoredOutputFormat recognizes whole-document pretty Claude JSON arrays
  ---
  duration_ms: 0.834644
  type: 'test'
  ...
# [2026-08-29 15:06:38.951 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/019-liveDetailsOpenCodeParser.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:38.981 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..7
# tests 7
# suites 0
# pass 7
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2087.673029

[20/311] packages/api/test/mergedPrTaskCancellation.test.ts
TAP version 13
# [webhook] Merged PR acme/widgets\#42: cancelled 3/3 active task(s)
# [webhook] Failed to cancel task for merged PR {
#   taskId: 'task-a',
#   repository: 'acme/widgets',
#   prNumber: 42,
#   error: Error: container stop blew up
#       at Object.stopTask (/home/runner/work/propr/propr/packages/api/test/mergedPrTaskCancellation.test.ts:89:34)
#       at stopNext (/home/runner/work/propr/propr/packages/api/webhookHandler.ts:210:35)
#       at <anonymous> (/home/runner/work/propr/propr/packages/api/webhookHandler.ts:236:104)
#       at Function.from (<anonymous>)
#       at cancelActiveTasksForMergedPR (/home/runner/work/propr/propr/packages/api/webhookHandler.ts:236:27)
#       at async TestContext.<anonymous> (/home/runner/work/propr/propr/packages/api/test/mergedPrTaskCancellation.test.ts:94:19)
#       at async Test.run (node:internal/test_runner/test:1054:7)
#       at async Test.processPendingSubtests (node:internal/test_runner/test:744:7)
# }
# [webhook] Task task-a for merged PR acme/widgets\#42 was stopped but the cancellation was not durably recorded; the abort signal remains for the worker to observe
# [webhook] Merged PR acme/widgets\#42: cancelled 2/3 active task(s), 1 failed
# [webhook] Task task-a for merged PR acme/widgets\#42 was no longer active
# [webhook] Merged PR acme/widgets\#42: cancelled 2/3 active task(s), 1 no longer active
# [webhook] Merged PR acme/widgets\#42: cancelled 2/3 active task(s), 1 stopped without a durable record
# [webhook] Event received: pull_request, action: closed, repo: acme/widgets, delivery: delivery-hxjxtsndw45
# [webhook] Merged PR acme/widgets\#42: cancelled 3/3 active task(s)
# [webhook] Event received: pull_request, action: closed, repo: acme/widgets, delivery: delivery-6do98xi7tq
# [webhook] Event received: pull_request, action: closed, repo: acme/widgets, delivery: delivery-w7unbx80b4j
# [webhook] Merge-triggered task cancellation failed {
#   repository: 'acme/widgets',
#   prNumber: 42,
#   error: Error: database unavailable
#       at Object.getActiveTasksForPR (/home/runner/work/propr/propr/packages/api/test/mergedPrTaskCancellation.test.ts:202:46)
#       at cancelActiveTasksForMergedPR (/home/runner/work/propr/propr/packages/api/webhookHandler.ts:187:50)
#       at handleWebhookRequest (/home/runner/work/propr/propr/packages/api/webhookHandler.ts:333:28)
#       at async TestContext.<anonymous> (/home/runner/work/propr/propr/packages/api/test/mergedPrTaskCancellation.test.ts:207:3)
#       at async Test.run (node:internal/test_runner/test:1054:7)
#       at async Test.processPendingSubtests (node:internal/test_runner/test:744:7)
# }
# Subtest: isMergedPullRequestClose only matches merged PR close events
ok 1 - isMergedPullRequestClose only matches merged PR close events
  ---
  duration_ms: 1.303136
  type: 'test'
  ...
# Subtest: cancelActiveTasksForMergedPR stops every active task and queued job with the merge reason
ok 2 - cancelActiveTasksForMergedPR stops every active task and queued job with the merge reason
  ---
  duration_ms: 2.931002
  type: 'test'
  ...
# Subtest: cancelActiveTasksForMergedPR does nothing when there is no active work
ok 3 - cancelActiveTasksForMergedPR does nothing when there is no active work
  ---
  duration_ms: 0.923095
  type: 'test'
  ...
# Subtest: cancelActiveTasksForMergedPR continues cancelling after a task fails to stop
ok 4 - cancelActiveTasksForMergedPR continues cancelling after a task fails to stop
  ---
  duration_ms: 3.805846
  type: 'test'
  ...
# Subtest: cancelActiveTasksForMergedPR counts no-longer-active tasks as skipped
ok 5 - cancelActiveTasksForMergedPR counts no-longer-active tasks as skipped
  ---
  duration_ms: 0.535592
  type: 'test'
  ...
# Subtest: cancelActiveTasksForMergedPR surfaces stops without a durable cancellation record separately
ok 6 - cancelActiveTasksForMergedPR surfaces stops without a durable cancellation record separately
  ---
  duration_ms: 0.468412
  type: 'test'
  ...
# Subtest: handleWebhookRequest cancels active tasks when a PR is merged
ok 7 - handleWebhookRequest cancels active tasks when a PR is merged
  ---
  duration_ms: 1.930314
  type: 'test'
  ...
# Subtest: handleWebhookRequest does not cancel anything for an unmerged PR close
ok 8 - handleWebhookRequest does not cancel anything for an unmerged PR close
  ---
  duration_ms: 0.356988
  type: 'test'
  ...
# Subtest: handleWebhookRequest still succeeds when the PR task lookup fails entirely
ok 9 - handleWebhookRequest still succeeds when the PR task lookup fails entirely
  ---
  duration_ms: 1.104192
  type: 'test'
  ...
# [2026-08-29 15:06:41.147 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/020-mergedPrTaskCancellation.test.ts/propr.test.sqlite"
#     environment: "test"
1..9
# tests 9
# suites 0
# pass 9
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2031.879365

[21/311] packages/api/test/notificationManagementRoutes.test.ts
TAP version 13
# Subtest: notification subscription management routes
    # Subtest: lists safe metadata and revokes an owned opaque subscription ID
    ok 1 - lists safe metadata and revokes an owned opaque subscription ID
      ---
      duration_ms: 3.072401
      type: 'test'
      ...
    # Subtest: sanitizes preference snapshots at both response boundaries
    ok 2 - sanitizes preference snapshots at both response boundaries
      ---
      duration_ms: 0.973559
      type: 'test'
      ...
    # Subtest: warns distinctly and without secrets for invalid VAPID configuration
    ok 3 - warns distinctly and without secrets for invalid VAPID configuration
      ---
      duration_ms: 1.6445
      type: 'test'
      ...
    1..3
ok 1 - notification subscription management routes
  ---
  duration_ms: 6.696037
  type: 'suite'
  ...
# [2026-08-29 15:06:43.389 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/tmp/propr-test-suite-3MoIu5/021-notificationManagementRoutes.test.ts/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 15:06:43.390 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
1..1
# tests 3
# suites 1
# pass 3
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 2110.651789

[22/311] packages/api/test/notificationProjectionService.test.ts
TAP version 13
# Subtest: notification lifecycle projection
    # Subtest: creates exactly one plan-ready event for the draft owner
    ok 1 - creates exactly one plan-ready event for the draft owner
      ---
      duration_ms: 169.773984
      type: 'test'
      ...
    # Subtest: separates implementation, review, and sanitized PR-attention events
    ok 2 - separates implementation, review, and sanitized PR-attention events
      ---
      duration_ms: 193.556696
      type: 'test'
      ...
    # Subtest: ignores stale task transitions and emits one stalled event per unchanged activity
    ok 3 - ignores stale task transitions and emits one stalled event per unchanged activity
      ---
      duration_ms: 139.816154
      type: 'test'
      ...
    # Subtest: projects a task failure once without copying error details
    ok 4 - projects a task failure once without copying error details
      ---
      duration_ms: 127.848446
      type: 'test'
      ...
    # Subtest: does not advertise Open PR when a trusted GitHub URL cannot be constructed
    ok 5 - does not advertise Open PR when a trusted GitHub URL cannot be constructed
      ---
      duration_ms: 129.836014
      type: 'test'
      ...
    # Subtest: advertises follow-up only with the stored repository and issue identity the endpoint requires
    ok 6 - advertises follow-up only with the stored repository and issue identity the endpoint requires
      ---
      duration_ms: 152.147471
      type: 'test'
      ...
    # Subtest: advertises review follow-up only when the endpoint issue is the reviewed PR
    ok 7 - advertises review follow-up only when the endpoint issue is the reviewed PR
      ---
      duration_ms: 157.508736
      type: 'test'
      ...
    # Subtest: restricts indexing failures to administrators
    ok 8 - restricts indexing failures to administrators
      ---
      duration_ms: 137.576034
      type: 'test'
      ...
    # Subtest: deduplicates one unhealthy period and allows a later failure after recovery
    ok 9 - deduplicates one unhealthy period and allows a later failure after recovery
      ---
      duration_ms: 142.402047
      type: 'test'
      ...
    # Subtest: logs and isolates projection persistence failures
    ok 10 - logs and isolates projection persistence failures
      ---
 

...(truncated)

View Workflow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant