Wave 0 item W0-8. The Marketing home is now business content only, and widgets are omitted (not locked) for users without read.
Configuration Status and Agent Activity are off the home. They stay defined, gated on marketing.admin.read (HIDDEN), and are exposed as the public MarketingWidgets.ADMIN_WIDGETS for a host to place on its Admin area.
Needs Attention gets one row per active channel that cannot send (transport not registered or not operational/test-only): "Sends on are paused - ask an admin", linking to the channel record. Nothing when every channel can send. No provider detail appears on the business page.
Every widget (home and the two record widgets) now requires marketing.read, HIDDEN, through a new MarketingPermissionChecker (QQQ widget rules can only express <base>.hasAccess, so a custom checker is the only way to require a read permission; same pattern as qbit-alerts). Base.render no longer emits "You need marketing.read ..."; it throws permission denied as defense in depth.
Agent Activity judgement: the "drafts/findings created" outcome column is arguably business content, but the same rows carry model/tool calls and tokens, and failed runs already surface in Needs Attention. I moved the whole widget; if a business-facing "agent prepared N drafts" is wanted, it should be a new small widget or KPI tile (audit item 2).
Rubric item moved
A1 0 -> 1 and A8 0 -> 1 on Marketing (marketing)
Audit rows fixed
Marketing (marketing) - Content app home:
A1: "marketing_configuration_status lists integrations with status/detail (provider configuration, A-0); marketing_agent_activity reports model/tool calls and tokens (system usage)..."
A8: "Locked shell: Base.render returns "You need marketing.read to see marketing data." instead of omitting the widget for users with access but no read"
Tests
./mvnw -o verify: 98 tests, 0 failures (BUILD SUCCESS; guardrails included). New in ComponentsTest: home widget list is exactly Needs Attention + Campaigns (no configuration status, no agent activity); a user with app access but no read gets no permission for any read-requiring widget and render refuses with no "You need" text; a reader gets the home widgets but not the admin ones; admins can still render the moved widgets; the blocked-channel row appears only when a channel is blocked (and the existing starter-data test now expects the row for the starter email channel, whose transport is configured but unverified).
Screenshots
Widget-level preview (unit-test render into standalone HTML, Playwright), before/after at 390, 768, 1024, 1440, 1920, 3200, attached locally: C:/Users/james/AppData/Local/Temp/claude/R--Git-Local-KofTwentyTwo-Praetor/83da0ae2-628c-4edb-9fd7-a93d49e86d27/scratchpad/dashboard-standard/pr-shots/qbit-marketing-business-home (before-<w>.png shows the old home widgets Needs Attention + Agent Activity + Configuration Status; after-<w>.png shows Needs Attention with the blocked channel). Full-page shots happen when kof22 pins the release.
Release
A qbit-marketing release is needed (next RC after 0.1.0-RC.6, the version Website-Backend pins on origin/main). kof22 then bumps qbit-marketing.version and, in a follow-up (not done here), places MarketingWidgets.ADMIN_WIDGETS on an Admin page. Until then the two moved widgets are not shown anywhere.
## Summary
Wave 0 item W0-8. The Marketing home is now business content only, and widgets are omitted (not locked) for users without read.
- **Configuration Status** and **Agent Activity** are off the home. They stay defined, gated on `marketing.admin.read` (HIDDEN), and are exposed as the public `MarketingWidgets.ADMIN_WIDGETS` for a host to place on its Admin area.
- **Needs Attention** gets one row per active channel that cannot send (transport not registered or not operational/test-only): "Sends on <channel> are paused - ask an admin", linking to the channel record. Nothing when every channel can send. No provider detail appears on the business page.
- Every widget (home and the two record widgets) now requires `marketing.read`, HIDDEN, through a new `MarketingPermissionChecker` (QQQ widget rules can only express `<base>.hasAccess`, so a custom checker is the only way to require a read permission; same pattern as qbit-alerts). `Base.render` no longer emits "You need marketing.read ..."; it throws permission denied as defense in depth.
- Agent Activity judgement: the "drafts/findings created" outcome column is arguably business content, but the same rows carry model/tool calls and tokens, and failed runs already surface in Needs Attention. I moved the whole widget; if a business-facing "agent prepared N drafts" is wanted, it should be a new small widget or KPI tile (audit item 2).
## Rubric item moved
A1 0 -> 1 and A8 0 -> 1 on Marketing (`marketing`)
## Audit rows fixed
Marketing (`marketing`) - Content app home:
- A1: "`marketing_configuration_status` lists integrations with status/detail (provider configuration, A-0); `marketing_agent_activity` reports model/tool calls and tokens (system usage)..."
- A8: "Locked shell: `Base.render` returns "You need marketing.read to see marketing data." instead of omitting the widget for users with access but no read"
## Tests
`./mvnw -o verify`: 98 tests, 0 failures (BUILD SUCCESS; guardrails included). New in `ComponentsTest`: home widget list is exactly Needs Attention + Campaigns (no configuration status, no agent activity); a user with app access but no read gets no permission for any read-requiring widget and render refuses with no "You need" text; a reader gets the home widgets but not the admin ones; admins can still render the moved widgets; the blocked-channel row appears only when a channel is blocked (and the existing starter-data test now expects the row for the starter email channel, whose transport is configured but unverified).
## Screenshots
Widget-level preview (unit-test render into standalone HTML, Playwright), before/after at 390, 768, 1024, 1440, 1920, 3200, attached locally: `C:/Users/james/AppData/Local/Temp/claude/R--Git-Local-KofTwentyTwo-Praetor/83da0ae2-628c-4edb-9fd7-a93d49e86d27/scratchpad/dashboard-standard/pr-shots/qbit-marketing-business-home` (`before-<w>.png` shows the old home widgets Needs Attention + Agent Activity + Configuration Status; `after-<w>.png` shows Needs Attention with the blocked channel). Full-page shots happen when kof22 pins the release.
## Release
A qbit-marketing release is needed (next RC after 0.1.0-RC.6, the version Website-Backend pins on origin/main). kof22 then bumps `qbit-marketing.version` and, in a follow-up (not done here), places `MarketingWidgets.ADMIN_WIDGETS` on an Admin page. Until then the two moved widgets are not shown anywhere.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Wave 0 item W0-8. The Marketing home is now business content only, and widgets are omitted (not locked) for users without read.
marketing.admin.read(HIDDEN), and are exposed as the publicMarketingWidgets.ADMIN_WIDGETSfor a host to place on its Admin area.marketing.read, HIDDEN, through a newMarketingPermissionChecker(QQQ widget rules can only express<base>.hasAccess, so a custom checker is the only way to require a read permission; same pattern as qbit-alerts).Base.renderno longer emits "You need marketing.read ..."; it throws permission denied as defense in depth.Rubric item moved
A1 0 -> 1 and A8 0 -> 1 on Marketing (
marketing)Audit rows fixed
Marketing (
marketing) - Content app home:marketing_configuration_statuslists integrations with status/detail (provider configuration, A-0);marketing_agent_activityreports model/tool calls and tokens (system usage)..."Base.renderreturns "You need marketing.read to see marketing data." instead of omitting the widget for users with access but no read"Tests
./mvnw -o verify: 98 tests, 0 failures (BUILD SUCCESS; guardrails included). New inComponentsTest: home widget list is exactly Needs Attention + Campaigns (no configuration status, no agent activity); a user with app access but no read gets no permission for any read-requiring widget and render refuses with no "You need" text; a reader gets the home widgets but not the admin ones; admins can still render the moved widgets; the blocked-channel row appears only when a channel is blocked (and the existing starter-data test now expects the row for the starter email channel, whose transport is configured but unverified).Screenshots
Widget-level preview (unit-test render into standalone HTML, Playwright), before/after at 390, 768, 1024, 1440, 1920, 3200, attached locally:
C:/Users/james/AppData/Local/Temp/claude/R--Git-Local-KofTwentyTwo-Praetor/83da0ae2-628c-4edb-9fd7-a93d49e86d27/scratchpad/dashboard-standard/pr-shots/qbit-marketing-business-home(before-<w>.pngshows the old home widgets Needs Attention + Agent Activity + Configuration Status;after-<w>.pngshows Needs Attention with the blocked channel). Full-page shots happen when kof22 pins the release.Release
A qbit-marketing release is needed (next RC after 0.1.0-RC.6, the version Website-Backend pins on origin/main). kof22 then bumps
qbit-marketing.versionand, in a follow-up (not done here), placesMarketingWidgets.ADMIN_WIDGETSon an Admin page. Until then the two moved widgets are not shown anywhere.🤖 Generated with Claude Code