Skip to content

fix(desktop): propagate canonical deep-link length validation to UX - #1983

Merged
integry merged 1 commit into
1951-epic-desktop-experience-uxsfrom
1952-epic-electron-runtime-app
Aug 29, 2026
Merged

fix(desktop): propagate canonical deep-link length validation to UX#1983
integry merged 1 commit into
1951-epic-desktop-experience-uxsfrom
1952-epic-electron-runtime-app

Conversation

@integry

@integry integry commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Propagates the final canonical deep-link serialization invariant into the UX epic after its earlier runtime sync.

This is the exact d99f006 runtime patch: canonical length/control checks, raw/canonical route equivalence, and boundary tests. It targets only the non-main UX epic branch. Related: #1951 #1952 #1979.

…8dcb68971e6a0e6`.

Implemented F1 only on base head `48f85811addf4bccfd390961e8dcb68971e6a0e6`.

Changes:

- [security.ts](/tmp/git-processor/worktrees/integry/propr/pr-1979-followup-2026-08-29T20-41-29/apps/desktop/src/security.ts) now checks the serialized canonical candidate’s length/controls and requires its dashboard path to equal the validated input path before returning it.
- Added desktop and renderer regressions for percent-expansion beyond 2,048 and an exactly 2,048-character valid canonical link.
- Existing traversal, encoded-delimiter, auth/pairing, query, and hash tests remain passing.

Verification:

- Desktop tests: 28 passed.
- Focused renderer tests: 5 passed.
- Desktop and UI typechecks: passed.
- Production package: passed.
- `git diff --check`: passed.
- Packaged smoke: environment-blocked because no usable Chromium sandbox helper is installed/configured.
- Full suite: reached file 155/320 before blocking on unavailable Redis (`127.0.0.1:6379`); neither Redis nor Docker is installed.

Only the three scoped files are modified. Per instruction, I did not commit or push; the system must publish the resulting branch head.

PR: #1979
Comment by: @integry (ID: 5464771154)
Model: gpt-5.6-sol
@github-actions

Copy link
Copy Markdown

Checks Failed

Validation failed during setup, tests, CLI packaging, linting, or build checks.

View Logs
Build check diagnostics for run 33274821553, attempt 1
Checkout outcome: success

--- GitHub Actions workflow lint ---
docker.io/rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667: Pulling from rhysd/actionlint
589002ba0eae: Pulling fs layer
c09af8888d6a: Pulling fs layer
4ccd7d76ca98: Pulling fs layer
b6b4b7b0e257: Pulling fs layer
b6b4b7b0e257: Waiting
c09af8888d6a: Verifying Checksum
c09af8888d6a: Download complete
4ccd7d76ca98: Verifying Checksum
4ccd7d76ca98: Download complete
589002ba0eae: Verifying Checksum
589002ba0eae: Download complete
589002ba0eae: Pull complete
c09af8888d6a: Pull complete
b6b4b7b0e257: Verifying Checksum
b6b4b7b0e257: Download complete
4ccd7d76ca98: Pull complete
b6b4b7b0e257: Pull complete
Digest: sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
Status: Downloaded newer image for rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667
docker.io/rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667

--- Release shell script lint ---

--- Toolchain ---
v22.23.2
10.9.8

--- Dependency installation ---
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated glob@7.2.3: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
npm warn deprecated gar@1.0.4: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
npm warn deprecated rimraf@2.6.3: Rimraf versions prior to v4 are no longer supported

added 1136 packages, and audited 1145 packages in 20s

326 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- Fast unit tests ---
Running fast unit tests (no Redis/Docker dependencies)...

> propr@0.8.15 test:unit
> NODE_ENV=test npx tsx --experimental-test-module-mocks --test test/minimal.test.ts test/modelName.test.ts test/agentContainerResources.test.ts test/agentDockerfileSupplyChain.test.ts test/daemonEventIntake.test.ts test/databaseMigrationGate.test.ts test/generateContext.test.ts test/githubEventIntakeMode.test.ts test/intakeModePrerequisites.test.ts test/orchestratorMigrationPhase.test.mjs test/validateRoutingUrl.test.ts test/routingWebSocketProtocol.test.ts test/routingWebSocketIntakeService.test.ts test/routingStatusPublisher.test.ts test/releaseValidation.test.mjs test/sessionSecret.test.ts test/testSuiteRunner.test.mjs packages/api/test/connectAuth.test.ts packages/api/test/attachmentUploadCleanup.test.ts packages/api/test/configReloadSubscription.test.ts packages/api/test/dockerCommandSafety.test.ts packages/api/test/listenAddress.test.ts packages/api/test/oauthState.test.ts packages/api/test/requestRateLimits.test.ts packages/api/test/statusRoutes.test.ts packages/api/test/agentRuntimeRoutes.test.ts packages/api/test/instanceAuthorization.test.ts packages/api/test/routeAuthorization.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: 5.916341
      type: 'test'
      ...
    # Subtest: persists a failed state when queue submission fails
    ok 2 - persists a failed state when queue submission fails
      ---
      duration_ms: 1.152059
      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: 1.032877
      type: 'test'
      ...
    # Subtest: times out slow runtime package validation before queueing
    ok 4 - times out slow runtime package validation before queueing
      ---
      duration_ms: 7.680679
      type: 'test'
      ...
    # Subtest: returns package suggestions from configured runtimes
    ok 5 - returns package suggestions from configured runtimes
      ---
      duration_ms: 1.46882
      type: 'test'
      ...
    # Subtest: enforces PROPR_ADMIN_USERS when configured
    ok 6 - enforces PROPR_ADMIN_USERS when configured
      ---
      duration_ms: 0.404689
      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.392165
      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.461126
      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.667914
      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: 3.578745
      type: 'test'
      ...
    # Subtest: resolves the runtime build queue lazily when queueing
    ok 11 - resolves the runtime build queue lazily when queueing
      ---
      duration_ms: 1.131691
      type: 'test'
      ...
    # Subtest: reports apply load failures through the route response
    ok 12 - reports apply load failures through the route response
      ---
      duration_ms: 0.488196
      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.585779
      type: 'test'
      ...
    # Subtest: rejects runtime verification without runtime-management permission
    ok 14 - rejects runtime verification without runtime-management permission
      ---
      duration_ms: 0.376962
      type: 'test'
      ...
    1..14
ok 1 - agent runtime package routes
  ---
  duration_ms: 27.639011
  type: 'suite'
  ...
# [2026-08-29 20:58:29.369 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/home/runner/work/propr/propr/data/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 20:58:29.392 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# Subtest: upload handler removes Multer files rejected before attachment processing
ok 2 - upload handler removes Multer files rejected before attachment processing
  ---
  duration_ms: 7.382604
  type: 'test'
  ...
# Subtest: attachment processing removes temporary and final files when persistence fails
ok 3 - attachment processing removes temporary and final files when persistence fails
  ---
  duration_ms: 6.291207
  type: 'test'
  ...
# Subtest: temporary cleanup refuses paths outside its configured root
ok 4 - temporary cleanup refuses paths outside its configured root
  ---
  duration_ms: 1.002135
  type: 'test'
  ...
# Subtest: temporary cleanup rejects dot-segment paths that resolve above its root
ok 5 - temporary cleanup rejects dot-segment paths that resolve above its root
  ---
  duration_ms: 0.899223
  type: 'test'
  ...
# Subtest: attachment processing rejects path-like draft IDs and still cleans its temp file
ok 6 - attachment processing rejects path-like draft IDs and still cleans its temp file
  ---
  duration_ms: 2.835302
  type: 'test'
  ...
# [2026-08-29 20:58:28.963 +0000] �[32mINFO�[39m: �[36mCreated data directory for SQLite database�[39m
#     directory: "/home/runner/work/propr/propr/data"
# [2026-08-29 20:58:29.373 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/home/runner/work/propr/propr/data/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 20:58:29.395 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# Subtest: API config subscription serializes the startup reload with settings updates
ok 7 - API config subscription serializes the startup reload with settings updates
  ---
  duration_ms: 6.442539
  type: 'test'
  ...
# Subtest: API config subscription reloads repository updates
ok 8 - API config subscription reloads repository updates
  ---
  duration_ms: 0.501838
  type: 'test'
  ...
# Subtest: API config subscription ignores unrelated and malformed events
ok 9 - API config subscription ignores unrelated and malformed events
  ---
  duration_ms: 0.341576
  type: 'test'
  ...
# Subtest: a failed API settings reload does not block the next notification
ok 10 - a failed API settings reload does not block the next notification
  ---
  duration_ms: 0.441459
  type: 'test'
  ...
# Subtest: relay tunnel mode uses Connect without local OAuth credentials
ok 11 - relay tunnel mode uses Connect without local OAuth credentials
  ---
  duration_ms: 4.8626
  type: 'test'
  ...
# Subtest: relay tunnel mode preserves Connect for operator-supplied service endpoints
ok 12 - relay tunnel mode preserves Connect for operator-supplied service endpoints
  ---
  duration_ms: 0.351543
  type: 'test'
  ...
# Subtest: local relay mode uses Connect without a per-instance OAuth App
ok 13 - local relay mode uses Connect without a per-instance OAuth App
  ---
  duration_ms: 0.409935
  type: 'test'
  ...
# Subtest: off-tunnel relay inference rejects callbacks outside the exact loopback allowlist
ok 14 - off-tunnel relay inference rejects callbacks outside the exact loopback allowlist
  ---
  duration_ms: 0.537813
  type: 'test'
  ...
# Subtest: off-tunnel custom relay enrollment does not infer hosted Connect auth
ok 15 - off-tunnel custom relay enrollment does not infer hosted Connect auth
  ---
  duration_ms: 0.241767
  type: 'test'
  ...
# Subtest: literal example OAuth placeholders do not enable GitHub web auth
ok 16 - literal example OAuth placeholders do not enable GitHub web auth
  ---
  duration_ms: 0.22409
  type: 'test'
  ...
# Subtest: explicit custom GitHub web auth remains supported
ok 17 - explicit custom GitHub web auth remains supported
  ---
  duration_ms: 0.272526
  type: 'test'
  ...
# Subtest: explicit custom GitHub web auth wins over relay inference off-tunnel
ok 18 - explicit custom GitHub web auth wins over relay inference off-tunnel
  ---
  duration_ms: 0.27834
  type: 'test'
  ...
# Subtest: Connect authorization URL carries the exact callback and CSRF state
ok 19 - Connect authorization URL carries the exact callback and CSRF state
  ---
  duration_ms: 0.763407
  type: 'test'
  ...
# Subtest: redeems a Connect code server-to-server without exposing the relay token in the body
ok 20 - redeems a Connect code server-to-server without exposing the relay token in the body
  ---
  duration_ms: 34.164853
  type: 'test'
  ...
# Subtest: binds the Connect identity username to the validated token owner
ok 21 - binds the Connect identity username to the validated token owner
  ---
  duration_ms: 1.122177
  type: 'test'
  ...
# Subtest: accepts Docker IDs and ProPR-generated container names
ok 22 - accepts Docker IDs and ProPR-generated container names
  ---
  duration_ms: 1.180831
  type: 'test'
  ...
# Subtest: rejects container references that could be parsed as options or shell syntax
ok 23 - rejects container references that could be parsed as options or shell syntax
  ---
  duration_ms: 0.204126
  type: 'test'
  ...
# Subtest: production subprocess call sites do not invoke a command shell
ok 24 - production subprocess call sites do not invoke a command shell
  ---
  duration_ms: 123.892402
  type: 'test'
  ...
# Subtest: no-shell guard rejects aliases and enabled shell options
ok 25 - no-shell guard rejects aliases and enabled shell options
  ---
  duration_ms: 16.197467
  type: 'test'
  ...
# 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: 21.363526
      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: 6.972315
      type: 'test'
      ...
    # Subtest: grants full admin permissions to PROPR_ADMIN_USERS
    ok 3 - grants full admin permissions to PROPR_ADMIN_USERS
      ---
      duration_ms: 3.603414
      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: 4.058213
      type: 'test'
      ...
    # Subtest: resolves demo users without installation permissions
    ok 5 - resolves demo users without installation permissions
      ---
      duration_ms: 3.223857
      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.994173
      type: 'test'
      ...
    # Subtest: current-user responses expose capabilities without OAuth credentials
    ok 7 - current-user responses expose capabilities without OAuth credentials
      ---
      duration_ms: 2.695314
      type: 'test'
      ...
    1..7
ok 26 - instance authorization
  ---
  duration_ms: 46.61222
  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: 5.360034
      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: 10.914347
      type: 'test'
      ...
    # Subtest: adds explicit members and writes an audit entry
    ok 3 - adds explicit members and writes an audit entry
      ---
      duration_ms: 10.049792
      type: 'test'
      ...
    # Subtest: keeps environment authority separate from durable role assignments
    ok 4 - keeps environment authority separate from durable role assignments
      ---
      duration_ms: 3.682438
      type: 'test'
      ...
    # Subtest: prevents removing the last durable administrator
    ok 5 - prevents removing the last durable administrator
      ---
      duration_ms: 6.552048
      type: 'test'
      ...
    # Subtest: allows role changes once another administrator exists
    ok 6 - allows role changes once another administrator exists
      ---
      duration_ms: 7.614562
      type: 'test'
      ...
    1..6
ok 27 - instance member service
  ---
  duration_ms: 44.71815
  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.896909
      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: 2.454901
      type: 'test'
      ...
    1..2
ok 28 - instance catalog
  ---
  duration_ms: 5.501552
  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: 4.030981
      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: 2.00324
      type: 'test'
      ...
    # Subtest: rejects GitHub usernames with trailing or consecutive hyphens
    ok 3 - rejects GitHub usernames with trailing or consecutive hyphens
      ---
      duration_ms: 2.205758
      type: 'test'
      ...
    1..3
ok 29 - instance admin routes
  ---
  duration_ms: 8.401149
  type: 'suite'
  ...
# [2026-08-29 20:58:31.939 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/home/runner/work/propr/propr/data/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 20:58:32.038 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# Subtest: direct API execution binds to loopback by default
ok 30 - direct API execution binds to loopback by default
  ---
  duration_ms: 2.328674
  type: 'test'
  ...
# Subtest: containerized API execution remains reachable through its published port
ok 31 - containerized API execution remains reachable through its published port
  ---
  duration_ms: 0.224365
  type: 'test'
  ...
# Subtest: an explicit API listen host overrides environment defaults
ok 32 - an explicit API listen host overrides environment defaults
  ---
  duration_ms: 0.202499
  type: 'test'
  ...
# Subtest: GitHub OAuth authorization stores and sends a random state nonce
ok 33 - GitHub OAuth authorization stores and sends a random state nonce
  ---
  duration_ms: 3.41551
  type: 'test'
  ...
# Subtest: GitHub OAuth callback rejects a mismatched state before token exchange
ok 34 - GitHub OAuth callback rejects a mismatched state before token exchange
  ---
  duration_ms: 1.143488
  type: 'test'
  ...
# [2026-08-29 20:58:33.973 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/home/runner/work/propr/propr/data/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 20:58:33.974 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# Subtest: returns a standard 429 response after the configured quota
ok 35 - returns a standard 429 response after the configured quota
  ---
  duration_ms: 232.768154
  type: 'test'
  ...
# Subtest: does not charge CORS preflight requests against the quota
ok 36 - does not charge CORS preflight requests against the quota
  ---
  duration_ms: 15.985148
  type: 'test'
  ...
# Subtest: route-level webhook limiting preserves alternate-case raw bodies and rejects excess requests before parsing
ok 37 - route-level webhook limiting preserves alternate-case raw bodies and rejects excess requests before parsing
  ---
  duration_ms: 19.518312
  type: 'test'
  ...
# Subtest: does not let an unconfigured private peer rotate quota buckets with X-Forwarded-For
ok 38 - does not let an unconfigured private peer rotate quota buckets with X-Forwarded-For
  ---
  duration_ms: 14.360151
  type: 'test'
  ...
# Subtest: tunnel trust does not let an unrelated private peer rotate quota buckets
ok 39 - tunnel trust does not let an unrelated private peer rotate quota buckets
  ---
  duration_ms: 20.110053
  type: 'test'
  ...
# Subtest: trusted TLS proxy preserves per-client quotas and secure session cookies
ok 40 - trusted TLS proxy preserves per-client quotas and secure session cookies
  ---
  duration_ms: 16.080587
  type: 'test'
  ...
# Subtest: resolves secure defaults and explicit positive-integer overrides
ok 41 - resolves secure defaults and explicit positive-integer overrides
  ---
  duration_ms: 0.646608
  type: 'test'
  ...
# Subtest: rejects invalid overrides instead of silently disabling protection
ok 42 - rejects invalid overrides instead of silently disabling protection
  ---
  duration_ms: 0.739976
  type: 'test'
  ...
# Subtest: assembled instance permission routes
    # Subtest: captures Express 5 named wildcard parameters as path segments
    ok 1 - captures Express 5 named wildcard parameters as path segments
      ---
      duration_ms: 44.205309
      type: 'test'
      ...
    # Subtest: members can read only the sanitized catalog endpoints
    ok 2 - members can read only the sanitized catalog endpoints
      ---
      duration_ms: 89.215285
      type: 'test'
      ...
    # Subtest: administrators pass every management guard in the route matrix
    ok 3 - administrators pass every management guard in the route matrix
      ---
      duration_ms: 36.721557
      type: 'test'
      ...
    1..3
ok 43 - assembled instance permission routes
  ---
  duration_ms: 171.735901
  type: 'suite'
  ...
# [2026-08-29 20:58:33.799 +0000] �[32mINFO�[39m: �[36mSQLite database connection established successfully�[39m
#     filename: "/home/runner/work/propr/propr/data/propr.test.sqlite"
#     environment: "test"
# [2026-08-29 20:58:33.967 +0000] �[32mINFO�[39m: �[36mSQLite database connection closed�[39m
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status omits disabled configured agents
ok 44 - /api/status omits disabled configured agents
  ---
  duration_ms: 1877.465469
  type: 'test'
  ...
# Subtest: /api/compatibility returns public version contract metadata
ok 45 - /api/compatibility returns public version contract metadata
  ---
  duration_ms: 3.614177
  type: 'test'
  ...
# Subtest: /api/desktop/discovery adds only the stable product name to compatibility metadata
ok 46 - /api/desktop/discovery adds only the stable product name to compatibility metadata
  ---
  duration_ms: 1.268891
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status returns default Claude fallback when no agents are configured
ok 47 - /api/status returns default Claude fallback when no agents are configured
  ---
  duration_ms: 2.724174
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# [notifications] Failed to project system health snapshot: Error: notification persistence unavailable
#     at projectSystemSnapshot (/home/runner/work/propr/propr/packages/api/test/statusRoutes.test.ts:254:13)
#     at Object.getStatus (/home/runner/work/propr/propr/packages/api/routes/statusRoutes.ts:192:14)
#     at async readStatus (/home/runner/work/propr/propr/packages/api/test/statusRoutes.test.ts:162:3)
#     at async TestContext.<anonymous> (/home/runner/work/propr/propr/packages/api/test/statusRoutes.test.ts:251:16)
#     at async Test.run (node:internal/test_runner/test:1054:7)
#     at async Test.processPendingSubtests (node:internal/test_runner/test:744:7)
# Subtest: /api/status isolates system notification projection failures
ok 48 - /api/status isolates system notification projection failures
  ---
  duration_ms: 4.923612
  type: 'test'
  ...
# Subtest: /api/status surfaces unified agent image outages
ok 49 - /api/status surfaces unified agent image outages
  ---
  duration_ms: 1.433321
  type: 'test'
  ...
# Subtest: /api/status includes warnings field in demo mode
ok 50 - /api/status includes warnings field in demo mode
  ---
  duration_ms: 1.100358
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status caches agent health checks briefly
ok 51 - /api/status caches agent health checks briefly
  ---
  duration_ms: 3.364451
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status reports resolved auth mode and event intake mode
ok 52 - /api/status reports resolved auth mode and event intake mode
  ---
  duration_ms: 1.919494
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status reports connected intake status when routing state is live
ok 53 - /api/status reports connected intake status when routing state is live
  ---
  duration_ms: 4.785195
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status reports disconnected intake status when routing state is down
ok 54 - /api/status reports disconnected intake status when routing state is down
  ---
  duration_ms: 2.069162
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status reports active intake status for polling when the daemon is running
ok 55 - /api/status reports active intake status for polling when the daemon is running
  ---
  duration_ms: 1.742631
  type: 'test'
  ...
# Subtest: /api/status reports disconnected intake status for polling when the daemon is stopped
ok 56 - /api/status reports disconnected intake status for polling when the daemon is stopped
  ---
  duration_ms: 1.415481
  type: 'test'
  ...
# Subtest: /api/status includes routing state published by the daemon
ok 57 - /api/status includes routing state published by the daemon
  ---
  duration_ms: 1.35733
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status exposes only validated UI-safe Connect account fields
ok 58 - /api/status exposes only validated UI-safe Connect account fields
  ---
  duration_ms: 1.745626
  type: 'test'
  ...
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Error loading summarization warnings: SqliteError: select * from `system_configs` where `key` = 'summarization_runtime_state' limit 1 - no such table: system_configs
#     at Database.prepare (/home/runner/work/propr/propr/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
#     at Client_BetterSQLite3._query (/home/runner/work/propr/propr/node_modules/knex/lib/dialects/better-sqlite3/index.js:35:34)
#     at executeQuery (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/query-executioner.js:37:17)
#     at Client_BetterSQLite3.query (/home/runner/work/propr/propr/node_modules/knex/lib/client.js:154:12)
#     at Runner.query (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:141:36)
#     at ensureConnectionCallback (/home/runner/work/propr/propr/node_modules/knex/lib/execution/internal/ensure-connection-callback.js:13:17)
#     at Runner.ensureConnection (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:318:20)
#     at async Runner.run (/home/runner/work/propr/propr/node_modules/knex/lib/execution/runner.js:30:19)
#     at async getConfigWithClient (/home/runner/work/propr/propr/packages/core/src/config/configStore.ts:17:24)
#     at async loadSummarizationRuntimeState (/home/runner/work/propr/propr/packages/core/src/config/configManagerSummarization.ts:101:19) {
#   code: 'SQLITE_ERROR'
# }
# Subtest: /api/status rejects impossible account dates and preserves valid leap-day instants
ok 59 - /api/status rejects impossible account dates and preserves valid leap-day instants
  ---
  duration_ms: 5.437713
  type: 'test'
  ...
# Subtest: /api/status drops malformed or disconnected Connect account state without assuming Community
ok 60 - /api/status drops malformed or disconnected Connect account state without assuming Community
  ---
  duration_ms: 2.895356
  type: 'test'
  ...
# Subtest: /api/status does not expose Connect account state for a non-Connect intake mode
ok 61 - /api/status does not expose Connect account state for a non-Connect intake mode
  ---
  duration_ms: 1.570716
  type: 'test'
  ...
# Subtest: /api/status reports connected githubAuth for relay-auth deployments
ok 62 - /api/status reports connected githubAuth for relay-auth deployments
  ---
  duration_ms: 1.322122
  type: 'test'
  ...
# Subtest: /api/status reports unknown auth mode and disconnected health when the resolver is bypassed
ok 63 - /api/status reports unknown auth mode and disconnected health when the resolver is bypassed
  ---
  duration_ms: 1.461577
  type: 'test'
  ...
# Subtest: /api/status omits malformed routing state
ok 64 - /api/status omits malformed routing state
  ---
  duration_ms: 1.418375
  type: 'test'
  ...
# Subtest: /api/status omits routing state with a malformed lastAckAt timestamp
ok 65 - /api/status omits routing state with a malformed lastAckAt timestamp
  ---
  duration_ms: 1.328508
  type: 'test'
  ...
# Subtest: /api/status omits routing state when none is published
ok 66 - /api/status omits routing state when none is published
  ---
  duration_ms: 1.352652
  type: 'test'
  ...
# Subtest: /api/status reports demo auth mode in demo mode
ok 67 - /api/status reports demo auth mode in demo mode
  ---
  duration_ms: 1.923026
  type: 'test'
  ...
# Error loading summarization warnings: S

...(truncated)

View Workflow

@integry integry added the AI label Aug 29, 2026
@integry

integry commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

/review

Review exact head d99f006 propagated from the runtime epic into UX epic branch 1951. Verify the three-file delta is exactly the canonical deep-link serialization fix plus focused regressions, preserves the desktop UX architecture and deterministic tests, and introduces no semantic conflict. Reproduce canonical length boundaries and re-audit encoded traversal/auth/reserved/external rejection. No code changes. Report blockers and score only after exact-head checks.

@propr-dev

propr-dev Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@integry integry removed the AI label Aug 29, 2026
@propr-dev

propr-dev Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

🔍 AI Code Review — codex:gpt-5.6-sol

Overall Evaluation

The three-file delta correctly applies canonical deep-link serialization validation and adds focused, deterministic regressions without changing the desktop delivery architecture. No semantic conflict or PR-introduced blocker is evident. The code itself needs no verified changes, but the PR is not currently merge-ready because the authoritative head status includes a failed Validate Changes check and two pending test suites.

Canonical form is revalidatedapps/desktop/src/security.ts:143 validates the raw route, then checks the serialized url.href for the 2,048-character/control-character limits and equivalent dashboard routing.

Exact boundary behavior is covered — Both changed test files demonstrate that Unicode expansion beyond 2,048 characters is rejected while an already-canonical link of exactly 2,048 characters is accepted and routed correctly.

Security and architecture remain intact — Re-audit confirms encoded traversal, credentials, reserved parameters, and external-path forms remain rejected; accepted links still travel through the existing main-process, IPC, and renderer navigation path.

Merge blockers

No merge blockers.

Suggestions

These are optional follow-ups and are not sent to /fix.

No suggestions.

Score

The implementation is correct and well-focused within scope, but the current failed validation check prevents a merge-ready rating until its cause is resolved; the pending suites should also complete successfully.

Score: 7/10


🤖 Review Details

  • Model: GPT-5.6 Sol
  • Time: 50s
  • Tokens: 29,293 (27,461 in / 1,832 out)
  • Cost: $0.15

View Task


💡 Next step: Comment /fix to address F# merge blockers only.
F# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. Suggestions require a separate ordinary follow-up request.

🤖 Review by ProPR

@integry integry added the AI label Aug 29, 2026
@integry

integry commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

/review

Re-review exact unchanged head d99f006 now that all nine exact-head checks, including rerun Validate Changes and Full Test Suite, are green. Confirm prior no-blocker canonical deep-link assessment, exact three-file propagation into UX epic, deterministic UI coverage, 673/674 serialization boundaries, and preserved security/runtime behavior. No code changes. Report final blockers and score from current evidence.

@propr-dev

propr-dev Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@integry integry removed the AI label Aug 29, 2026
@propr-dev

propr-dev Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

🔍 AI Code Review — codex:gpt-5.6-sol

Overall Evaluation

This exact three-file propagation correctly enforces canonical deep-link serialization without altering the desktop delivery architecture. It is ready to merge.

Canonical boundary enforcedapps/desktop/src/security.ts validates both raw and serialized links, rejecting canonical forms above 2,048 characters while accepting the exact limit. The 673/674 space-expansion cases serialize to 2,047/2,050 characters respectively.

Route semantics preserved — Open links are accepted only when raw and canonical forms resolve to the identical validated dashboard path, preserving traversal, authentication-route, reserved-parameter, external-route, and control-character protections.

Focused deterministic coverage — Both security and renderer-navigation tests cover expansion rejection and exact-limit acceptance, while all authoritative current-head checks pass.

Merge blockers

No merge blockers.

Suggestions

These are optional follow-ups and are not sent to /fix.

No suggestions.

Score

The implementation is narrowly scoped, security-preserving, well-covered at serialization boundaries, and fully green on current-head validation. No merge blockers or material verification gaps remain.

Score: 10/10


🤖 Review Details

  • Model: GPT-5.6 Sol
  • Time: 57s
  • Tokens: 29,370 (27,074 in / 2,296 out)
  • Cost: $0.16

View Task


💡 Next step: Comment /fix to address F# merge blockers only.
F# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. Suggestions require a separate ordinary follow-up request.

🤖 Review by ProPR

@integry
integry merged commit 7f9d5e2 into 1951-epic-desktop-experience-uxs Aug 29, 2026
85 of 86 checks passed
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.

1 participant