Skip to content

[3370 by Claude Opus 5.5] 0.9.0 release change: make the dashboard AI activity summary (the bar at the top of the dashboard showing Live/Paused/Saved/Syncing/Idle with text such as 'Gathering the latest activity…' or 'Activity overview is temporarily unavailable.',... - #3371

Merged
integry merged 5 commits into
mainfrom
3370/claude-opus-5-5-0-9-0-release-change-make-20261029-0715-387
Oct 29, 2026

Conversation

@propr-dev

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

Copy link
Copy Markdown
Contributor

AI Implementation Summary

Closes #3370

Branch: 3370/claude-opus-5-5-0-9-0-release-change-make-20261029-0715-387
Commits: ✅ Changes committed (9d1348e)


AI Processing Completed

Execution Details:

Summary:
That last notification was a wait task I'd started earlier; it adds nothing new. Lint, typecheck, release verify and the 42 Playwright tests were already confirmed passing in the summary above, and nothing has changed since.

Detailed Logs:

  • Conversation: 78 messages
  • Session: cc80b850-4389-45d9-aca6-b0e8f128f39f

Log files stored at:

  • conversation: /usr/src/app/logs/executions/issue-3370-2026-10-29T07-35-21-018Z-conversation.json
  • output: /usr/src/app/logs/executions/issue-3370-2026-10-29T07-35-21-018Z-output.txt
Latest Conversation Messages
ASSISTANT: The dashboard AI summary is now an opt-in Experimental feature, off by default. Its toggle and Voice briefings share one new **Experimental** section under Settings → General. Your branch was already ...

ASSISTANT: [content unavailable]

ASSISTANT: That last notification was a wait task I'd started earlier; it adds nothing new. Lint, typecheck, release verify and the 42 Playwright tests were already confirmed passing in the summary above, and no...


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


💡 Need changes?

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


Visual preview

After: dashboard with the setting unset

After: dashboard with the setting unset

No summary bar and no narrative request; the panes start directly under the toolbar.

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

After: Settings → General → Experimental

After: Settings → General → Experimental

One Experimental section containing Enable voice briefings and Dashboard AI summaries (unchecked by default), noting the summarization model and LLM cost.

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

After: AI Models & Reasoning → Planning

After: AI Models & Reasoning → Planning

The checkbox is removed from Model selection; the Summarization Model helper points to Experimental.

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

After: settings search for 'dashboard summary'

After: settings search for 'dashboard summary'

Searching 'dashboard summary' finds the Experimental section; 'experimental' and 'voice' find it too.

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

Before: dashboard with default settings

Before: dashboard with default settings

The AI activity summary bar showed above the panes by default.

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

Before: Settings → General

Before: Settings → General

Voice briefings had its own 'Voice briefings · Experimental' section; the dashboard summary toggle lived elsewhere.

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

Before: AI Models & Reasoning → Planning

Before: AI Models & Reasoning → Planning

The Dashboard summary checkbox sat under Model selection, checked by default.

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

…othing new. Lint, typecheck, release verify and the 42 Playwright tests were already confirmed passing in the summary above, and nothing has changed since.
@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR implements the default-off setting and groups the controls appropriately, but needs changes to the dashboard’s enablement gate before merge.

✅ Explicit opt-in — Production configuration reads enable summaries only for a saved boolean true.

✅ Isolated settings writes — Unrelated settings saves no longer implicitly persist dashboard_summary_enabled.

✅ Experimental grouping — Voice and dashboard controls share an Experimental section, with scope and LLM-cost explanations.

The supplied objective is truncated; this review evaluates its visible requirements and the changed behavior. Current checks report no failures, with nine pending. No commands or tests were run.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F1: 🔴 Cached opt-in bypasses current enablement

  • Required behavior: A disabled dashboard summary must render no bar and issue no narrative request.

  • Evidence: propr-ui/src/components/Dashboard/DashboardSummary.tsx, readEnabled and the enabled fallback.

    1. Open the dashboard while summaries are enabled; the status response stores true in session storage.
    2. Navigate to Settings and successfully disable dashboard summaries. The new toggle handler does not invalidate that stored status.
    3. Return to the dashboard in the same session. Before the status request completes, readEnabled(instance) returns the old true.
    4. The summary readout mounts and its existing hook immediately requests a narrative; cached prose can also appear despite the saved setting being off.

    The later status response hides the readout, but cannot prevent the initial render or request. Server-side gating prevents generation when disabled, but does not satisfy the client’s no-bar/no-request contract. The added tests cover an initially unconfirmed status, not a previously cached opt-in followed by disabling. Verification provenance: static trace: the changed gate, dedicated settings handler, and supplied useDashboardSummary mounting behavior.

  • Minimum fix: Require current enablement confirmation before mounting the narrative consumer. Cached prose can still be retained and displayed after confirmation.

F2: 🔴 Status failures permanently suppress recovery

  • Required behavior: A transient read failure must not leave an explicitly enabled feature unable to recover through the dashboard’s existing refresh behavior.

  • Evidence: propr-ui/src/components/Dashboard/DashboardSummary.tsx, the status effect and its [instance] dependency.

    1. Open the dashboard with the server setting explicitly enabled.
    2. The initial status request fails during a temporary connection interruption. The rejection handler converts the failure to false and stores that result in state and session storage.
    3. Connectivity returns and dashboard activity updates change activityToken.
    4. The status effect does not rerun because instance is unchanged, and the narrative consumer remains unmounted. Summaries stay absent until the dashboard remounts.

    Previously, the narrative hook could retry after activity changes; the new gate prevents that hook from mounting at all. Its retry and visibility handling therefore cannot recover this failure. The new rejection test verifies suppression but does not test subsequent recovery. Verification provenance: static trace: the changed effect dependencies and supplied dashboard caller and narrative hook.

  • Minimum fix: Distinguish an unavailable status from confirmed disablement and retry unavailable status on an existing recovery trigger, such as dashboard refresh activity or reconnect, while keeping the summary hidden until confirmation.

Suggestions

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

No suggestions.

Score

The configuration and settings changes are well scoped, but two enablement lifecycle defects remain. Added tests cover initial states without covering stale confirmation or recovery; current checks have no reported failures.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 1m 5s
  • Tokens: 58,313 (57,313 in / 1,000 out)
  • Cost: $0.51

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F1 F2

🤖 Review by ProPR

@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/fix
Keep it simple: the safest shape is to never mount the narrative consumer from a cached session flag (drop the sessionStorage opt-in cache entirely unless it is only used to show already-confirmed prose after a fresh confirmation), and to re-check status when activityToken changes or the page regains visibility while status is unavailable.

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit fa692c8

Addressed 1 AI review comment (IDs: 6490995671)

Addressed findings F1, F2

Summary of Changes

I fixed F1 and F2 in propr-ui/src/components/Dashboard/DashboardSummary.tsx and kept it simple, as you asked: the session-storage opt-in cache is gone entirely.

F1: a cached opt-in no longer mounts the summary. Every dashboard mount now asks the server for the setting. The bar and its narrative request only mount once that request says on. If you turn summaries off in Settings and come back, there is no bar and no narrative request. Prose saved in the narrative hook's own cache is still kept, but it only shows after a fresh on.

F2: a failed status check can now recover. The status now has four states: pending, on, off and unavailable. Only "unavailable" (the request failed) is checked again, and nothing shows until a check succeeds. A re-check happens when either of these occurs:

  • activityToken changes.
  • the page becomes visible again.

A confirmed off is not re-checked on activity, so a disabled summary makes no extra requests. The listener that watches for the page becoming visible is only attached while the status is unavailable.

Tests (DashboardSummary.test.tsx):

  • New tests:
    • After an earlier confirmed session, turning the setting off means a remount renders nothing and requests no narrative, both before and after the status reply.
    • Saved prose only appears after a fresh confirmation.
    • An unreadable status is re-checked on an activity change and again when the page becomes visible; it stays hidden until it returns on, and is not re-checked after that.
    • A confirmed off is not re-checked.
  • Changed test: "restores cached prose" now waits one tick for the status reply before checking for the prose.
  • Negative check: with the previous version of DashboardSummary.tsx swapped back in, the first three new tests fail.

Verification, all passing:

  • the Dashboard vitest files (108 tests).
  • eslint --max-warnings 0 on the Dashboard folder.
  • tsc --noEmit.
  • the dashboard-responsive and usage-tips Playwright specs (27 tests).

Nothing else in the UI, end-to-end tests or docs read the removed session key. I didn't capture previews: the bar looks the same, and the change only affects when it mounts.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @integry
  • Time: 5m 6s
  • Tokens: 442,990 (436,071 in / 6,919 out)
  • Cost: $0.43

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 6491003993✓

…hboardSummary.tsx` and kept it simple, as you asked: the session-storage opt-in cache is gone entirely.

I fixed F1 and F2 in `propr-ui/src/components/Dashboard/DashboardSummary.tsx` and kept it simple, as you asked: the session-storage opt-in cache is gone entirely.

**F1: a cached opt-in no longer mounts the summary.** Every dashboard mount now asks the server for the setting. The bar and its narrative request only mount once that request says `on`. If you turn summaries off in Settings and come back, there is no bar and no narrative request. Prose saved in the narrative hook's own cache is still kept, but it only shows after a fresh `on`.

**F2: a failed status check can now recover.** The status now has four states: pending, on, off and unavailable. Only "unavailable" (the request failed) is checked again, and nothing shows until a check succeeds. A re-check happens when either of these occurs:
- `activityToken` changes.
- the page becomes visible again.

A confirmed `off` is not re-checked on activity, so a disabled summary makes no extra requests. The listener that watches for the page becoming visible is only attached while the status is unavailable.

**Tests** (`DashboardSummary.test.tsx`):
- **New tests:**
  - After an earlier confirmed session, turning the setting off means a remount renders nothing and requests no narrative, both before and after the status reply.
  - Saved prose only appears after a fresh confirmation.
  - An unreadable status is re-checked on an activity change and again when the page becomes visible; it stays hidden until it returns `on`, and is not re-checked after that.
  - A confirmed `off` is not re-checked.
- **Changed test:** "restores cached prose" now waits one tick for the status reply before checking for the prose.
- **Negative check:** with the previous version of `DashboardSummary.tsx` swapped back in, the first three new tests fail.

**Verification, all passing:**
- the Dashboard vitest files (108 tests).
- `eslint --max-warnings 0` on the Dashboard folder.
- `tsc --noEmit`.
- the `dashboard-responsive` and `usage-tips` Playwright specs (27 tests).

Nothing else in the UI, end-to-end tests or docs read the removed session key. I didn't capture previews: the bar looks the same, and the change only affects when it mounts.

PR: #3371
Comment by: @integry (ID: 6491003993)
Model: Claude Opus 5.5
@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR makes dashboard AI summaries opt-in and groups them with experimental settings. It needs a localized recovery fix before merge.

✅ Explicit opt-in — Production configuration reads require true, and unrelated settings saves no longer persist the summary setting.

✅ Fresh confirmation — The dashboard waits for a fresh status response before mounting the narrative consumer, including when cached prose exists.

✅ Focused coverage — Added tests cover hidden defaults, fresh confirmation, and recovery from rejected status requests.

The supplied original objective is truncated; this review assesses its visible requirements and the supplied diff. Current checks show 37 passed, none failed, and one pending. No commands or tests were run.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F3: 🔴 Preserve unavailable status for recovery

  • Required behavior: A transient failure to read the opt-in must remain distinguishable from confirmed disablement so the new status gate can recover.

  • Evidence: packages/api/routes/dashboardRoutes.ts:getNarrativeStatus and propr-ui/src/components/Dashboard/DashboardSummary.tsx:recheckUnavailable

    1. An instance has summaries explicitly enabled, but its configuration read throws during the dashboard's initial status request.
    2. getNarrativeStatus catches the exception and returns a successful response containing { enabled: false }.
    3. The dashboard records this as 'off', rather than 'unavailable'.
    4. Configuration access recovers. Subsequent activity and visibility changes cannot retry the request because recheckUnavailable resets only 'unavailable', and the visibility listener is installed only for that state.

    The enabled feature consequently remains hidden until the component remounts. Request rejection recovery does not protect this sequence because the server converts the failure into success. The backend test explicitly expects this conversion, while the frontend recovery test mocks a rejection instead.

    static trace: verified across the new endpoint, response classification, and both retry effects in the supplied diff.

  • Minimum fix: Return a retryable error response when configuration cannot be read, or represent unavailability explicitly and map it to 'unavailable'. Preserve the hidden state until confirmation and add coverage connecting this backend failure to frontend recovery.

Suggestions

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

S1: 🟢 Align the remaining settings documentation

The Settings section of docs/docs/features/web-ui.md still places experimental voice controls under Integrations, contradicting the newly updated General → Experimental instructions earlier in that file. Updating that older navigation description would improve consistency; this documentation cleanup is non-blocking.

Score

The implementation covers the primary opt-in behavior well, but the new status endpoint defeats recovery from backend configuration failures. The correction is localized; current checks otherwise provide strong supporting evidence.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 46s
  • Tokens: 59,972 (59,256 in / 716 out)
  • Cost: $0.52

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F3 S1

🤖 Review by ProPR

@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/fix F3 S1
For F3, return a retryable non-2xx response (for example 503) from getNarrativeStatus when the setting cannot be read, so the UI maps it to 'unavailable'. Add a test that connects that backend failure to frontend recovery.

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 99f876d

Addressed 1 AI review comment (IDs: 6491778333)

Addressed finding F3 · suggestion S1

Summary of Changes

F3 and S1 are both fixed. When the summary setting can't be read, the dashboard now treats it as unavailable and checks again, so an enabled summary no longer stays hidden until the page is remounted.

F3: unreadable setting

  • Backend (packages/api/routes/dashboardRoutes.ts): getNarrativeStatus now returns 503 { error: 'Dashboard summary status is unavailable' } instead of a successful { enabled: false }. The frontend reads that error as 'unavailable', so the bar stays hidden and the existing re-checks (on new dashboard activity or when the page becomes visible again) keep running.
  • Backend test (packages/api/test/dashboardNarrativeStatus.test.ts): it used to expect enabled: false here; it now expects the 503 and its body.
  • Backend-to-frontend test (new file, propr-ui/src/components/Dashboard/DashboardSummary.statusRecovery.test.tsx): unlike the existing UI tests, it uses the real dashboard API client and only stubs the network. The status request first gets the same 503 the backend sends: nothing renders and no summary is requested. Once the setting becomes readable, the next activity change re-checks, gets { enabled: true }, and the bar appears with one summary request. The UI suite can't call the backend handler directly, so the two tests are tied together by using the same 503 body.
  • Negative check: I swapped the stub back to the old 200 { enabled: false } response and the new test failed (the bar never appeared), so it does catch this bug.
  • Other callers: DashboardSummary is the only caller of the status endpoint, so nothing else had the same problem.

S1: settings docs (docs/docs/features/web-ui.md): the Integrations bullet no longer lists experimental voice controls. A new General bullet says Experimental is where voice briefings and dashboard AI summaries are turned on. I also added General to the tab list in the line above, which otherwise wouldn't match the new bullet.

Checks: the backend status tests pass (2/2), the DashboardSummary UI tests pass (22/22), and ESLint with zero warnings plus tsc --noEmit pass for both packages/api and propr-ui. I didn't run the full suites.

There's nothing visible to capture, so I made no preview images.

Found separately, not changed: the main summary endpoint (getNarrative) has a similar fallback. When the setting can't be read, it returns enabled: true, summary: null. That was already there before this PR and wasn't part of F3, so I left it alone. I also didn't touch the OpenAPI entry for the status endpoint. It still says "not documented yet" and doesn't list the 503, though its generic error response covers it.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @integry
  • Time: 5m 35s
  • Tokens: 1,132,213 (1,124,258 in / 7,955 out)
  • Cost: $0.65

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 6491801694✓

… read, the dashboard now treats it as unavailable and checks again, so an enabled summary no longer stays hidden until the page is remounted.

F3 and S1 are both fixed. When the summary setting can't be read, the dashboard now treats it as unavailable and checks again, so an enabled summary no longer stays hidden until the page is remounted.

**F3: unreadable setting**
- **Backend** (`packages/api/routes/dashboardRoutes.ts`): `getNarrativeStatus` now returns `503 { error: 'Dashboard summary status is unavailable' }` instead of a successful `{ enabled: false }`. The frontend reads that error as `'unavailable'`, so the bar stays hidden and the existing re-checks (on new dashboard activity or when the page becomes visible again) keep running.
- **Backend test** (`packages/api/test/dashboardNarrativeStatus.test.ts`): it used to expect `enabled: false` here; it now expects the 503 and its body.
- **Backend-to-frontend test** (new file, `propr-ui/src/components/Dashboard/DashboardSummary.statusRecovery.test.tsx`): unlike the existing UI tests, it uses the real dashboard API client and only stubs the network. The status request first gets the same 503 the backend sends: nothing renders and no summary is requested. Once the setting becomes readable, the next activity change re-checks, gets `{ enabled: true }`, and the bar appears with one summary request. The UI suite can't call the backend handler directly, so the two tests are tied together by using the same 503 body.
- **Negative check:** I swapped the stub back to the old `200 { enabled: false }` response and the new test failed (the bar never appeared), so it does catch this bug.
- **Other callers:** `DashboardSummary` is the only caller of the status endpoint, so nothing else had the same problem.

**S1: settings docs** (`docs/docs/features/web-ui.md`): the Integrations bullet no longer lists experimental voice controls. A new **General** bullet says Experimental is where voice briefings and dashboard AI summaries are turned on. I also added **General** to the tab list in the line above, which otherwise wouldn't match the new bullet.

**Checks:** the backend status tests pass (2/2), the `DashboardSummary` UI tests pass (22/22), and ESLint with zero warnings plus `tsc --noEmit` pass for both `packages/api` and `propr-ui`. I didn't run the full suites.

There's nothing visible to capture, so I made no preview images.

**Found separately, not changed:** the main summary endpoint (`getNarrative`) has a similar fallback. When the setting can't be read, it returns `enabled: true, summary: null`. That was already there before this PR and wasn't part of F3, so I left it alone. I also didn't touch the OpenAPI entry for the status endpoint. It still says "not documented yet" and doesn't list the 503, though its generic error response covers it.

PR: #3371
Comment by: @integry (ID: 6491801694)
Model: Claude Opus 5.5
@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

Needs a localized correction before merge. The opt-in defaults and Settings organization are implemented well, but production configuration failures still bypass the new recovery behavior.

✅ Explicit opt-in persistence — Unrelated settings saves omit dashboard_summary_enabled; its dedicated toggle writes an explicit boolean.

✅ Fresh confirmation gate — The dashboard requests no narrative and renders no bar until status confirms enablement, with tests covering unavailable-status recovery.

The supplied original issue description is truncated, so requirements beyond its visible portion could not be assessed. The supplied diff was reviewed as complete. No commands or tests were run. Current checks report no failures, with 22 pending.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F4: 🔴 Production status reads suppress recoverable failures

  • Required behavior: The new status endpoint must distinguish an unreadable setting from confirmed disablement so transient failures remain recoverable.

  • Evidence: packages/api/server.ts:416, production isSummaryEnabled callback; packages/api/routes/dashboardRoutes.ts, getNarrativeStatus; propr-ui/src/components/Dashboard/DashboardSummary.tsx, recheckUnavailable.

    1. An instance has dashboard_summary_enabled explicitly enabled, but its configuration database read fails while a user opens the dashboard.
    2. The production callback calls getConfig('dashboard_summary_enabled', false). The supplied configStore.ts:20–39 implementation catches database and parsing failures and returns that fallback.
    3. Consequently, isSummaryEnabled resolves false instead of rejecting. getNarrativeStatus returns HTTP 200 with { enabled: false }; its new 503 catch branch never runs.
    4. The frontend stores 'off'. Once the database recovers, activity changes and visibility restoration cannot retry this status because recheckUnavailable only clears 'unavailable'. The enabled feature remains absent for that mounted dashboard.

    Verification provenance — static trace: followed the production dependency through the supplied configuration implementation, route, and frontend state transitions. The backend test injects a throwing callback, while the frontend recovery test injects a 503 response; neither exercises the production callback that suppresses the error. Their protections therefore do not cover this sequence.

  • Minimum fix: Use the existing strict configuration reader for the production enablement callback, preserving false for genuinely missing settings while propagating read/parse failures. Add regression coverage connecting that production read behavior to the status endpoint’s 503 and frontend retry.

Suggestions

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

No suggestions.

Score

The implementation substantially satisfies the visible objective and adds useful coverage, but the production failure path still prevents recovery after a transient configuration outage. Pending checks alone do not lower this assessment.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 50s
  • Tokens: 61,895 (61,132 in / 763 out)
  • Cost: $0.54

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F4

🤖 Review by ProPR

@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/fix F4
Use the existing strict configuration reader for the production isSummaryEnabled callback (missing setting → false; read/parse failure → reject → 503). Keep the change minimal.

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 9b028ca

Addressed 1 AI review comment (IDs: 6491971099)

Addressed finding F4

Summary of Changes

I fixed F4. The production isSummaryEnabled callback now uses core's existing strict reader, getConfigStrict. A missing dashboard_summary_enabled setting still means off. A failed read or an unparseable value now makes the callback throw, so getNarrativeStatus returns its retryable 503 instead of a 200 with { enabled: false }.

Changes

  • packages/core/src/config/configManager.ts: getConfigStrict is now exported from @propr/core alongside getConfig. It already existed in configStore.ts, but the package didn't expose it.
  • packages/api/routes/dashboardSummarySetting.ts (new, a few lines): isDashboardSummaryEnabled() returns (await getConfigStrict('dashboard_summary_enabled', false)) === true. I moved it out of the inline lambda so tests can exercise the production callback.
  • packages/api/server.ts: passes isSummaryEnabled: isDashboardSummaryEnabled and drops the now-unused getConfig import.
  • packages/api/test/dashboardNarrativeStatus.test.ts: a new regression test wires the real callback into getNarrativeStatus over a migrated SQLite database. It checks four states:
    • no setting → 200 { enabled: false }
    • true → 200 { enabled: true }
    • a value that isn't valid JSON → 503
    • the config table renamed away, simulating a failed read → 503, then 200 { enabled: true } once it's restored
  • DashboardSummary.statusRecovery.test.tsx: comment only. It now points to the backend test that produces the 503 body the frontend recovery test consumes, linking the two halves of the sequence in F4.

Verification

  • The new backend test passes (3/3 in that file).
  • Negative check: with getConfigStrict swapped back to getConfig, the new test fails, so it catches the original defect.
  • The frontend status-recovery test passes.
  • tsc --noEmit for packages/api passes after rebuilding core.
  • eslint --max-warnings 0 passes on the changed files in packages/api and packages/core.

Sibling check: getNarrative calls the same deps.isSummaryEnabled, so it now gets a rejection rather than a silent false. That lands in its existing try. The test suites that mock @propr/core copy the whole real module and only import the MCP server, so the new export doesn't affect them.

There's no visible UI change, so I didn't create a preview.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @integry
  • Time: 4m 24s
  • Tokens: 919,351 (911,915 in / 7,436 out)
  • Cost: $0.55

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 6491989832✓

…uses core's existing strict reader, `getConfigStrict`. A missing `dashboard_summary_enabled` setting still means off. A failed read or an unparseable value now makes the callback throw, so `getNarrativeStatus` returns its retryable 503 instead of a 200 with `{ enabled: false }`.

I fixed F4. The production `isSummaryEnabled` callback now uses core's existing strict reader, `getConfigStrict`. A missing `dashboard_summary_enabled` setting still means off. A failed read or an unparseable value now makes the callback throw, so `getNarrativeStatus` returns its retryable 503 instead of a 200 with `{ enabled: false }`.

**Changes**
- **`packages/core/src/config/configManager.ts`:** `getConfigStrict` is now exported from `@propr/core` alongside `getConfig`. It already existed in `configStore.ts`, but the package didn't expose it.
- **`packages/api/routes/dashboardSummarySetting.ts`** (new, a few lines): `isDashboardSummaryEnabled()` returns `(await getConfigStrict('dashboard_summary_enabled', false)) === true`. I moved it out of the inline lambda so tests can exercise the production callback.
- **`packages/api/server.ts`:** passes `isSummaryEnabled: isDashboardSummaryEnabled` and drops the now-unused `getConfig` import.
- **`packages/api/test/dashboardNarrativeStatus.test.ts`:** a new regression test wires the real callback into `getNarrativeStatus` over a migrated SQLite database. It checks four states:
  - no setting → 200 `{ enabled: false }`
  - `true` → 200 `{ enabled: true }`
  - a value that isn't valid JSON → 503
  - the config table renamed away, simulating a failed read → 503, then 200 `{ enabled: true }` once it's restored
- **`DashboardSummary.statusRecovery.test.tsx`:** comment only. It now points to the backend test that produces the 503 body the frontend recovery test consumes, linking the two halves of the sequence in F4.

**Verification**
- The new backend test passes (3/3 in that file).
- Negative check: with `getConfigStrict` swapped back to `getConfig`, the new test fails, so it catches the original defect.
- The frontend status-recovery test passes.
- `tsc --noEmit` for `packages/api` passes after rebuilding core.
- `eslint --max-warnings 0` passes on the changed files in `packages/api` and `packages/core`.

**Sibling check:** `getNarrative` calls the same `deps.isSummaryEnabled`, so it now gets a rejection rather than a silent false. That lands in its existing `try`. The test suites that mock `@propr/core` copy the whole real module and only import the MCP server, so the new export doesn't affect them.

There's no visible UI change, so I didn't create a preview.

PR: #3371
Comment by: @integry (ID: 6491989832)
Model: Claude Opus 5.5
@integry

integry commented Oct 29, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR makes dashboard AI summaries opt-in, groups them under Experimental settings, and preserves the existing API and summarization backend. It is merge-ready within the supplied scope, conditional on pending checks completing successfully.

✅ Explicit opt-in — Production enables summaries only for a saved boolean true; unrelated settings saves omit dashboard_summary_enabled.

✅ Safe recovery — The strict configuration reader propagates read and parse failures to a 503 response. The frontend remains hidden and retries unavailable status on activity or restored visibility.

✅ Fresh confirmation — The narrative consumer mounts only after status confirmation, with regression coverage for cached prose and backend failure recovery.

This was a static review; no commands or tests were run. The supplied issue objective is truncated, so requirements beyond its visible portion could not be assessed. Current checks report 29 passed, seven pending, and no failures.

Merge blockers

No merge blockers.

Suggestions

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

S2: 🟢 Align the route fallback

packages/api/routes/dashboardRoutes.ts, in getNarrativeStatus, defaults to enabled when isSummaryEnabled is omitted. Consider making the dependency mandatory or aligning the route factory’s defaults with the opt-in policy. This is optional because the production server explicitly supplies the strict reader; the supplied code does not demonstrate a production bypass.

Score

The visible implementation satisfies the opt-in behavior and includes focused regression coverage for confirmation and recovery. No merge-blocking defect was verified; pending checks still need to finish.

Score: 9/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 37s
  • Tokens: 62,057 (61,558 in / 499 out)
  • Cost: $0.53

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix S2

🤖 Review by ProPR

@propr-dev

propr-dev Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

CI failed: Validate Changes

Please investigate and fix this CI failure.

Failure evidence

.github:1142
Process completed with exit code 1.

propr-ui/e2e/mobile-voice-briefing.smoke.pw.ts:301 — e2e/mobile-voice-briefing.smoke.pw.ts:295:1 › shows the administrator opt-in under General

  1. e2e/mobile-voice-briefing.smoke.pw.ts:295:1 › shows the administrator opt-in under General ────

    Retry Epic: Claude-Powered GitHub Issue Processor - Stage 1: Authentication, Logging & Project Setup #1 ───────────────────────────────────────────────────────────────────────────────────────
    Error: expect(locator).toBeVisible() failed

    Locator: getByRole('heading', { name: 'Voice briefings · Experimental' })
    Expected: visible
    Timeout: 5000ms
    Error: element(s) not found

    Call log:

    • Expect "toBeVisible" with timeout 5000ms
    • waiting for getByRole('heading', { name: 'Voice briefings · Experimental' })

    299 |
    300 | const optIn = page.getByRole('checkbox', { name: 'Enable voice briefings' });

    301 | await expect(page.getByRole('heading', { name: 'Voice briefings · Experimental' })).toBeVisible();
    | ^
    302 | await expect(optIn).not.toBeChecked();
    303 | await expect(page.getByRole('button', { name: 'Voice briefing' })).toBeHidden();
    304 |
    at /home/runner/work/propr/propr/propr-ui/e2e/mobile-voice-briefing.smoke.pw.ts:301:87

propr-ui/e2e/mobile-voice-briefing.smoke.pw.ts:301 — e2e/mobile-voice-briefing.smoke.pw.ts:295:1 › shows the administrator opt-in under General

  1. e2e/mobile-voice-briefing.smoke.pw.ts:295:1 › shows the administrator opt-in under General ────
    Error: expect(locator).toBeVisible() failed

    Locator: getByRole('heading', { name: 'Voice briefings · Experimental' })
    Expected: visible
    Timeout: 5000ms
    Error: element(s) not found

    Call log:

    • Expect "toBe…

@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 40844272656, 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
589002ba0eae: Verifying Checksum
589002ba0eae: Download complete
4ccd7d76ca98: Verifying Checksum
4ccd7d76ca98: Download complete
589002ba0eae: Pull complete
b6b4b7b0e257: Verifying Checksum
b6b4b7b0e257: Download complete
c09af8888d6a: Pull 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.4
10.9.9

--- 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 gar@1.0.4: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
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

added 1107 packages, and audited 1116 packages in 20s

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

found 0 vulnerabilities

--- CLI release package ---
Verifying propr-cli release package...

> propr@0.9.0 cli:pack
> node packages/cli/scripts/build-publish.mjs


> @propr/shared@0.9.0 build
> tsc


> @propr/local-setup@0.9.0 build
> tsc


> @propr/cli@0.9.0 build
> tsc && node scripts/copy-assets.mjs

copy-assets: copied 9 file(s) into the CLI package.

Staged propr-cli@0.9.0 at /home/runner/work/propr/propr/dist-publish/propr-cli
npm notice
npm notice 📦  propr-cli@0.9.0
npm notice Tarball Contents
npm notice 26.7kB README.md
npm notice 36.3kB dist/agentSkill.js
npm notice 754B dist/api/agentRuntime.js
npm notice 7.1kB dist/api/agents.js
npm notice 2.6kB dist/api/agentTank.js
npm notice 4.0kB dist/api/automations.js
npm notice 11.7kB dist/api/client.js
npm notice 5.0kB dist/api/errors.js
npm notice 1.6kB dist/api/followupHandoffs.js
npm notice 16.9kB dist/api/goals.js
npm notice 6.0kB dist/api/implement.js
npm notice 2.6kB dist/api/index.js
npm notice 1.9kB dist/api/logs.js
npm notice 6.2kB dist/api/plans.js
npm notice 4.2kB dist/api/relay.js
npm notice 12.3kB dist/api/repos.js
npm notice 14.2kB dist/api/settings.js
npm notice 775B dist/api/stats.js
npm notice 1.6kB dist/api/syntheticPools.js
npm notice 1.8kB dist/api/system.js
npm notice 5.9kB dist/api/tasks.js
npm notice 2.9kB dist/api/todos.js
npm notice 86B dist/api/types.js
npm notice 313B dist/api/visualPreviewAuth.js
npm notice 30.2kB dist/assets/env.example.txt
npm notice 5.8kB dist/auth/githubLogin.js
npm notice 19.7kB dist/commands/agentCommands.js
npm notice 4.2kB dist/commands/agentPoolCommands.js
npm notice 4.3kB dist/commands/agentSkillCommands.js
npm notice 29.7kB dist/commands/agentValidation.js
npm notice 27.2kB dist/commands/automationCommands.js
npm notice 70.8kB dist/commands/checkCommands.js
npm notice 8.9kB dist/commands/configCommands.js
npm notice 14.6kB dist/commands/connectCommand.js
npm notice 5.5kB dist/commands/githubAppApi.js
npm notice 27.7kB dist/commands/githubAppCommands.js
npm notice 60.3kB dist/commands/goalCommands.js
npm notice 8.1kB dist/commands/handoffCommands.js
npm notice 2.4kB dist/commands/imageCommands.js
npm notice 8.0kB dist/commands/implementCommands.js
npm notice 1.8kB dist/commands/index.js
npm notice 7.3kB dist/commands/initCommands.js
npm notice 14.1kB dist/commands/initStack.js
npm notice 6.1kB dist/commands/logCommands.js
npm notice 24.9kB dist/commands/planCommands.js
npm notice 8.4kB dist/commands/relayCommands.js
npm notice 38.6kB dist/commands/repoCommands.js
npm notice 2.7kB dist/commands/repoValidate.js
npm notice 7.5kB dist/commands/runtimeCommands.js
npm notice 17.9kB dist/commands/settingCommands.js
npm notice 4.6kB dist/commands/setup/agentHostActions.js
npm notice 123B dist/commands/setup/agents.js
npm notice 4.7kB dist/commands/setup/engine.js
npm notice 51B dist/commands/setup/github.js
npm notice 37.3kB dist/commands/setup/hostActions.js
npm notice 3.2kB dist/commands/setup/imagePlatform.js
npm notice 27.3kB dist/commands/setup/sequential.js
npm notice 51B dist/commands/setup/state.js
npm notice 51B dist/commands/setup/types.js
npm notice 10.7kB dist/commands/setupCommand.js
npm notice 4.4kB dist/commands/stackCommands.js
npm notice 1.4kB dist/commands/startCommand.js
npm notice 3.7kB dist/commands/statsCommands.js
npm notice 13.5kB dist/commands/systemCommands.js
npm notice 3.5kB dist/commands/tankCommands.js
npm notice 46.3kB dist/commands/taskCommands.js
npm notice 29.7kB dist/commands/todoCommands.js
npm notice 31.0kB dist/commands/tunnelCommand.js
npm notice 2.7kB dist/commands/uiDocsCommands.js
npm notice 8.3kB dist/completion.js
npm notice 27.3kB dist/config/ConfigManager.js
npm notice 276B dist/config/index.js
npm notice 989B dist/config/rootKey.js
npm notice 345B dist/config/types.js
npm notice 46.0kB dist/connectIdentity.js
npm notice 25.0kB dist/connectRootAuthority.js
npm notice 32.5kB dist/connectWindowsAuthority.js
npm notice 2.2kB dist/desktopDiscovery.js
npm notice 13.3kB dist/desktopLocalSetup.js
npm notice 17.2kB dist/index.js
npm notice 4.5kB dist/native/darwin-authority-broker.c
npm notice 8.9kB dist/native/directory-operations.c
npm notice 50.1kB dist/native/prebuilds/darwin-arm64/connect-authority-broker
npm notice 54.2kB dist/native/prebuilds/darwin-arm64/directory-operations.node
npm notice 17.1kB dist/native/prebuilds/darwin-x64/connect-authority-broker
npm notice 24.3kB dist/native/prebuilds/darwin-x64/directory-operations.node
npm notice 28.9kB dist/native/prebuilds/linux-arm64/directory-operations.node
npm notice 17.4kB dist/native/prebuilds/linux-x64/directory-operations.node
npm notice 1.2kB dist/native/README.md
npm notice 3.1kB dist/orchestrator/format.js
npm notice 13.4kB dist/orchestrator/index.js
npm notice 302B dist/orchestrator/manifest.json
npm notice 129.0kB dist/orchestrator/orchestrator.mjs
npm notice 408B dist/orchestrator/types.js
npm notice 237B dist/skill/propr/agents/openai.yaml
npm notice 8.9kB dist/skill/propr/SKILL.md
npm notice 4.5kB dist/tui/AgentTableApp.js
npm notice 4.5kB dist/tui/app.js
npm notice 11.6kB dist/tui/CheckApp.js
npm notice 5.1kB dist/tui/render.js
npm notice 32.5kB dist/tui/SetupApp.js
npm notice 18.4kB dist/tui/SetupApp.test.js
npm notice 8.2kB dist/tui/StartApp.js
npm notice 3.6kB dist/utils/apiErrorPresentation.js
npm notice 12.0kB dist/utils/directoryDescriptor.js
npm notice 739B dist/utils/dockerPort.js
npm notice 5.0kB dist/utils/envFile.js
npm notice 520B dist/utils/index.js
npm notice 5.7kB dist/utils/io.js
npm notice 717B dist/utils/localSetupPlatform.js
npm notice 1.5kB dist/utils/nativeArtifact.js
npm notice 544B dist/utils/parseState.js
npm notice 417B dist/utils/positiveInteger.js
npm notice 4.5kB dist/utils/privateFilesystem.js
npm notice 4.2kB dist/utils/resolveProject.js
npm notice 7.2kB dist/vendor/local-setup/agents.js
npm notice 64.5kB dist/vendor/local-setup/engine.js
npm notice 5.0kB dist/vendor/local-setup/envFile.js
npm notice 11.4kB dist/vendor/local-setup/github.js
npm notice 188B dist/vendor/local-setup/index.js
npm notice 27.5kB dist/vendor/local-setup/publicInstanceIdentity.js
npm notice 14.6kB dist/vendor/local-setup/state.js
npm notice 2.8kB dist/vendor/local-setup/types.js
npm notice 1.0kB dist/vendor/shared/accountStatusTimestamp.js
npm notice 7.6kB dist/vendor/shared/activityEvents.js
npm notice 2.8kB dist/vendor/shared/agentConfigRedaction.js
npm notice 4.4kB dist/vendor/shared/agentDefinitions.js
npm notice 2.3kB dist/vendor/shared/agentFailureLine.js
npm notice 3.4kB dist/vendor/shared/agentLogin.js
npm notice 3.1kB dist/vendor/shared/agentTank.js
npm notice 1.2kB dist/vendor/shared/agentTankHistory.js
npm notice 2.8kB dist/vendor/shared/analyticsTimeframe.js
npm notice 4.1kB dist/vendor/shared/antigravityCompatibility.js
npm notice 5.1kB dist/vendor/shared/apiOrigin.js
npm notice 3.5kB dist/vendor/shared/assignment.js
npm notice 9.2kB dist/vendor/shared/automationDefinitions.js
npm notice 8.5kB dist/vendor/shared/connectDiscovery.js
npm notice 9.6kB dist/vendor/shared/cronSchedule.js
npm notice 254B dist/vendor/shared/demoMode.js
npm notice 4.3kB dist/vendor/shared/desktopPairing.js
npm notice 481B dist/vendor/shared/desktopTokenRevocation.js
npm notice 8.9kB dist/vendor/shared/events.js
npm notice 3.1kB dist/vendor/shared/extensionProfiles.js
npm notice 2.7kB dist/vendor/shared/fleetData.js
npm notice 2.5kB dist/vendor/shared/githubAppManifest.js
npm notice 1.6kB dist/vendor/shared/githubAuthMode.js
npm notice 2.0kB dist/vendor/shared/githubEventIntakeMode.js
npm notice 11.6kB dist/vendor/shared/goalBlockers.js
npm notice 6.0kB dist/vendor/shared/goalCheckpoints.js
npm notice 4.0kB dist/vendor/shared/goalCreation.js
npm notice 4.8kB dist/vendor/shared/goalWait.js
npm notice 13.0kB dist/vendor/shared/index.js
npm notice 214B dist/vendor/shared/instanceAuthorization.js
npm notice 54B dist/vendor/shared/instanceCatalog.js
npm notice 584B dist/vendor/shared/instanceStorage.js
npm notice 4.0kB dist/vendor/shared/intakeModePrerequisites.js
npm notice 2.9kB dist/vendor/shared/labelUtils.js
npm notice 17.1kB dist/vendor/shared/modelDefinitions.js
npm notice 3.5kB dist/vendor/shared/notificationLinks.js
npm notice 51.3kB dist/vendor/shared/notifications.js
npm notice 7.5kB dist/vendor/shared/previewStorage/v1.js
npm notice 866B dist/vendor/shared/projectSlug.js
npm notice 3.8kB dist/vendor/shared/proprCompatibility.js
npm notice 13.0kB dist/vendor/shared/proprServiceUrls.js
npm notice 16.6kB dist/vendor/shared/prTemplate.js
npm notice 2.2kB dist/vendor/shared/publishedVisualPreviews.js
npm notice 2.5kB dist/vendor/shared/reasoningLevels.js
npm notice 1.2kB dist/vendor/shared/repositoryIcon.js
npm notice 1.4kB dist/vendor/shared/repositoryIconUrl.js
npm notice 3.9kB dist/vendor/shared/repositoryPresentation.js
npm notice 9.5kB dist/vendor/shared/reviewContextBudget.js
npm notice 5.8kB dist/vendor/shared/reviewFeedbackIds.js
npm notice 1.7kB dist/vendor/shared/reviewPrompt.js
npm notice 907B dist/vendor/shared/runCostCap.js
npm notice 861B dist/vendor/shared/sessionSecret.js
npm notice 392B dist/vendor/shared/sqliteTimestamp.js
npm notice 603B dist/vendor/shared/statusKeys.js
npm notice 7.5kB dist/vendor/shared/syntheticAgents.js
npm notice 2.2kB dist/vendor/shared/taskIdentifiers.js
npm notice 1.8kB dist/vendor/shared/taskLifecycle.js
npm notice 733B dist/vendor/shared/taskReplacement.js
npm notice 957B dist/vendor/shared/text.js
npm notice 9.8kB dist/vendor/shared/usageTips.catalog.json
npm notice 5.0kB dist/vendor/shared/usageTips.js
npm notice 335B dist/vendor/shared/usageTypes.js
npm notice 1.1kB dist/vendor/shared/userWhitelist.js
npm notice 758B dist/vendor/shared/validateRelayUrl.js
npm notice 2.2kB dist/vendor/shared/validateRoutingUrl.js
npm notice 7.1kB dist/vendor/shared/visualPreviewCapacity.js
npm notice 9.3kB dist/vendor/shared/voice.js
npm notice 222B dist/vendor/shared/workEvidence.js
npm notice 675B package.json
npm notice Tarball Details
npm notice name: propr-cli
npm notice version: 0.9.0
npm notice filename: propr-cli-0.9.0.tgz
npm notice package size: 482.4 kB
npm notice unpacked size: 2.0 MB
npm notice shasum: 2aed4e2a56ab63974cdbf597024aa753bcf319ff
npm notice integrity: sha512-hazws8ivD1S0W[...]yEv/XYQdM+4cw==
npm notice total files: 192
npm notice
propr-cli-0.9.0.tgz

Dry run only. Re-run with --publish to publish to npm.
✅ propr-cli release package verified

--- Stage outcomes ---
Workflow lint: success
Release shell lint: success
Pre-setup gate: skipped
Node setup: success
Toolchain: success
Dependency install: success
Release metadata: success
CLI packaging: success
Change detection: success
Changed-area checks: skipped

View Workflow

@propr-dev

propr-dev Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 360ada7

Processed 2 comments:

  • Comment 1 by @propr-dev[bot] (ID: 6493197693✓)
  • Comment 2 by @github-actions[bot] (ID: 6493198428✓)

Summary of Changes

I fixed the Validate Changes failure. It was the test that was out of date, not the app.

Cause: This PR moved the administrator's voice briefings opt-in into the new shared Experimental section under General. The non-admin account view still uses its own "Voice briefings · Experimental" heading. The smoke test shows the administrator opt-in under General still looked for that old heading on the admin Settings page, so it couldn't find it.

Fix: In propr-ui/e2e/mobile-voice-briefing.smoke.pw.ts:301, the test now checks for the Experimental heading, matched exactly. The rest of the test is unchanged: the "Enable voice briefings" checkbox starts unchecked, the Voice briefing button is hidden, and checking the box shows the button.

Verification: I ran mobile-voice-briefing.smoke.pw.ts in Playwright and both of its tests pass. ESLint with --max-warnings 0 is clean on that file. I didn't make previews because only a test changed, so there's nothing new to see.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @propr-dev[bot], @github-actions[bot]
  • Time: 3m 21s
  • Tokens: 389,520 (387,683 in / 1,837 out)
  • Cost: $0.31

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment IDs: 6493197693✓, 6493198428✓

…was out of date, not the app.

I fixed the Validate Changes failure. It was the test that was out of date, not the app.

**Cause:** This PR moved the administrator's voice briefings opt-in into the new shared **Experimental** section under General. The non-admin account view still uses its own "Voice briefings · Experimental" heading. The smoke test `shows the administrator opt-in under General` still looked for that old heading on the admin Settings page, so it couldn't find it.

**Fix:** In `propr-ui/e2e/mobile-voice-briefing.smoke.pw.ts:301`, the test now checks for the `Experimental` heading, matched exactly. The rest of the test is unchanged: the "Enable voice briefings" checkbox starts unchecked, the Voice briefing button is hidden, and checking the box shows the button.

**Verification:** I ran `mobile-voice-briefing.smoke.pw.ts` in Playwright and both of its tests pass. ESLint with `--max-warnings 0` is clean on that file. I didn't make previews because only a test changed, so there's nothing new to see.

PR: #3371
Comment by: @propr-dev[bot] (ID: 6493197693)
Comment by: @github-actions[bot] (ID: 6493198428)
Model: Claude Opus 5.5
@integry
integry merged commit 700ce82 into main Oct 29, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant