Skip to content

feat(governance): add capabilities.social_share pin for share cards - #8565

Merged
bolichen97 merged 1 commit into
mainfrom
feat/social-share-governance-gate
Sep 5, 2026
Merged

feat(governance): add capabilities.social_share pin for share cards#8565
bolichen97 merged 1 commit into
mainfrom
feat/social-share-governance-gate

Conversation

@CrysisDeu

@CrysisDeu CrysisDeu commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a governance switch for the "Share as image" feature (PR #8040) so a fleet administrator can turn it off wholesale: a new capabilities.social_share capability row, resolved server-side and enforced at the only place the feature can be enforced — the dashboard entry.

{"version": 1, "boot": {"fail_closed": true},
 "capabilities": {"social_share": {"enabled": false}}}

What the feature sends off the machine (the point of the switch)

Audit of website/src/pages/chat/share/:

  • Card render + PNG export — entirely in the browser (html-to-image over a DOM node). The PNG is copied to the clipboard or downloaded. No upload anywhere.
  • Intent buttons — open https://x.com/intent/post?text=… and https://www.linkedin.com/feed/?shareActive=true&text=… in a new tab. The caption text (derived from the assistant reply) leaves the machine in the URL to a third-party site. This is the egress governance needs to be able to close.
  • /logo.png — fetched from the gateway itself (same origin), not egress.

There is no server-side share handler (no render, store, or POST endpoint exists), so there is no backend action to return 403 from. The control is the entry itself.

How it is enforced

Backend

  • capabilities.social_share SCOPE_CATALOG row, capability_default=True, data-only (no CONTRACT_VERSION / evaluator change). A policy that never mentions the row keeps the entry; naming it with enabled: false withdraws it.
  • src/kiro_crew/dashboard/social_share.py — the probe, the shape handlers/mobile_connect.py uses for the same job (a dashboard read that hides an entry): evaluated through vet_and_audit on the pinned dashboard:ui surface key (never a caller-controlled header), every denied decision honoured whichever layer produced it (a profile bound to the dashboard surface can withdraw the entry), and fail-closed (an unevaluable ceiling hides the entry and is recorded as the denial it produces).
  • GET /api/dashboard/config gains a read-only social_share_enabled. Resolved off-thread. The field is dropped from the PUT body (both settings surfaces round-trip the whole GET), so it can never be written — governance, not config, owns the answer.
  • SEL: every evaluation leaves a governance_decision row (tool dashboard_config_social_share), grant and denial alike — the read is the enforcement here. The endpoint is not polled (mount / focus / stale window / generation change only).
  • Mid-session ceiling swap: policy_distribution.apply_ceiling can replace the ceiling without a restart, so the WS slots frame now carries governanceGeneration alongside gitlabHostsGeneration (one builder, both frames). Every dashboard-user socket's existing 5s status pusher (_push_status) compares the counter each tick and requests a coalesced slots push when it moves — no extra task per socket (First Principles subtraction adopted), and kept out of the owner-only credential-refresh driver so a non-owner-only window is reached too. The initial frame and the tick's baseline are seeded from ONE read, so a swap during connection setup registers as a change rather than becoming the baseline silently. useWebSocket invalidates ['dashboardConfig'] on a change and on each connection's first frame. A withdrawn entry disappears within one 5s tick instead of waiting out the 30s stale window.
  • In-flight intent: openIntent re-reads the permission from a ref AFTER the export awaits; if policy withdrew sharing meanwhile, the pre-opened tab is closed and the caption is never handed to the third-party URL.

Known limitation (deliberate): the invalidation channel follows the ceiling generation, which set_context bumps on every policy install. A profile-layer (Level 2) tightening — an operator editing a local profile file — is honoured by the probe but does not bump that counter, so the dashboard converges on the cached dashboardConfig's schedule (30s stale window, window focus, or the next slot mutation) rather than on the next watcher tick. Profiles are operator-local files, not the fleet push channel, and every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) converges on the same schedule. Tracked as a follow-up in #8623 (a profile_generation() bumped by the ProfileStore on reload, compared alongside the ceiling generation).

Frontend

  • AssistantMessage takes shareEnabled; ChatPage passes dashCfg.social_share_enabled === true from the ['dashboardConfig'] query it already runs — no new fetch. The entry stays hidden until the server has answered (endpoint is the authority, same posture as the mobile-connect rail row). An absent prop also hides it, so a host that forgets the wire fails closed.
  • When Share was the menu's only item (loaded window keeps fork/plan as row buttons), the More actions trigger is withdrawn with it rather than opening an empty menu. Fork/plan are untouched by the pin.
  • Policy swap mid-compose (UX lane): if the ceiling flips while the share dialog is open, the dialog is NOT unmounted (it is mounted outside the overflow menu and independent of shareEnabled). The user's edited caption stays in place, the four share actions are disabled, and a notice says why and tells the user to copy their text now — it is not saved on close (pages.chat.share.withdrawn_by_policy, 12 locales + en-XA). A plain-text Copy text affordance in the notice (local clipboard, no image, no third-party site) keeps one salvage path, so Close never means silent loss; it copies everything the user could have edited here — the caption AND the card's contenteditable text (question when included, excerpt), since those edits vanish on close just like the caption does. When the clipboard refuses (plain-HTTP hosts; a thrown legacy fallback is caught too) the button reports Copy failed, a status line says the clipboard is blocked, that the post text is selected — press Ctrl+C / ⌘C — and that card edits must be copied from the card itself, and the caption is selected so that keystroke is the next thing the user does — the one button the notice points at never sits inert. The notice is actor-neutral ("Sharing was turned off by policy") because the probe honours an operator's own profile pin as well as a fleet ceiling (all UX suggestions on the prior heads, implemented).
  • Ceiling viewer label (UX lane Watch): SCOPE_LABEL_KEY in SecurityPanel.tsx gains capabilities.social_sharegov_scope_social_share ("Share as image", same string as the menu entry, 12 locales + en-XA), so the Security panel's row — the one place a user can learn why Share vanished — names the feature they lost instead of falling through to the untranslated "Social Share" leaf.
  • The Security panel's governance viewer picks the row up automatically (api_governance_policy iterates SCOPE_CATALOG; label falls back to the humanised leaf "Social share").

Screenshots

Same reply, same hover — the only difference is the stubbed social_share_enabled.

Permitted (default): More actions opens with Share as image.

More actions menu with Share as image

Pinned off by policy: the action row keeps copy / link / fork / plan / speak / raw / regenerate; the More actions trigger (whose only item was Share) is gone.

Action row without the More actions trigger

Policy withdrawn while composing: the dialog stays with the edited caption, the share actions are disabled, the notice names the cause and offers a plain-text copy.

Share dialog kept open after a policy swap, with a notice and disabled actions

Captured by website/scripts/capture-social-share-governance.mjs (fixture harness, no gateway).

Docs

  • docs/system-specs/modules/governance.md — capability list + a capabilities.social_share section (why the chokepoint is a read, fail-closed rationale, audit-on-change, policy-layer-only).
  • docs/feature-map/README.md — share row now names the governance scope and the endpoint it is read from.

Tests

  • test/test_social_share_governance.py — catalog row; probe through the real evaluator (ungoverned, policy silent, policy pin, dashboard-bound profile deny, degrade, unexpected error + its audit row); pinned surface key; GET reports true/false; every decision audited; PUT tolerates the round-tripped field and never persists it; _slots_ws_frame carries governanceGeneration.
  • test/test_dashboard_state_ws.py — owner and dashboard frames carry the same governanceGeneration.
  • website/src/test/AssistantMessage.test.tsx — Share only while permitted; absent prop fails closed; trigger withdrawn when Share was the only item and returns when permitted.
  • website/src/pages/chat/share/ShareMessageModal.test.tsx — a mid-compose withdrawal keeps the dialog and its edited caption, disables all four share actions, shows the notice, keeps the plain-text copy path working (caption and the edited card text ride along), and does not close on the user's behalf; a refused clipboard on that copy path reports the failure and selects the caption instead of looking like success; a withdrawal that lands during an in-flight export closes the pre-opened tab and never navigates it to the intent URL.
  • website/src/test/useWebSocketGitlabHosts.test.tsdashboardConfig invalidated on a governance-generation change and on a reconnect's first frame.
  • website/src/pages/settings/SecurityPanel.test.tsx — a pinned capabilities.social_share row is labelled "Share as image", not the humanised "Social Share" leaf.

Local verification was lint-only per the current desk rule (isort / flake8 / mypy --platform linux / black gate / tsc -b / eslint / docs-lint / brand gate all clean); test verification is on CI for this head.

no linked issue: governance follow-up requested directly on #8040's feature.

@CrysisDeu
CrysisDeu requested a review from a team September 4, 2026 21:34
@CrysisDeu
CrysisDeu requested a review from a team as a code owner September 4, 2026 21:34
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of 8a9e8a92c81506ab9c12464725766d470eb701b8 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

UX-Verdict: PASS

The withdrawal path is honest and protective: the notice names what happened, salvages the user's edits, and the entry disappears cleanly when pinned off.

The mid-compose screenshot confirms the hard case works: "Sharing was turned off by policy. Copy your text now…" asserts the state the code holds, offers an adjacent "Copy text" action with copied/failed feedback, and the clipboard-blocked fallback pre-selects the caption. Menu withdrawal avoids an empty dropdown, the modal survives the policy flip without destroying edits, and the Security panel row is named after the menu entry a user actually lost. All 12 locales carry the new strings.

[UX-REVIEWED] 8a9e8a9

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 8a9e8a92c81506ab9c12464725766d470eb701b8 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: PASS

A UI-only affordance is governed at the only chokepoint it has, using the established capability-row shape, with the gaps disclosed rather than papered over.

Watch

  • The control is inherently advisory at the browser boundary — a user can copy text and open x.com themselves; the row removes the one-click egress affordance, not the egress. The spec's "the read is the enforcement" phrasing is accurate for this feature but should not become precedent for governing anything with a real server-side action.

Suggestions

  • temp-screenshots/ commits ~750KB of PNGs into the repo history solely to back description links; host them on the PR instead so they don't ship in every future clone.

[DESIGN-REVIEWED] 8a9e8a9

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 8a9e8a92c81506ab9c12464725766d470eb701b8 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All verification checks are done: governance_generation() pre-exists, the mobile_connect precedent matches the claimed shape, temp-screenshots/ is an established convention, and the gitlab-hosts watch is genuinely owner-only (so the new dashboard-user watch is not a second spelling of it). Here is the review.

First-Principles-Verdict: PASS

A fleet-forbiddable egress path (caption text to X/LinkedIn) gets its one possible chokepoint — the entry itself — with every item declared and derived.

What this change ships

Intent: let a fleet administrator turn off the "Share as image" feature wholesale. ADDITION.

  1. A policy pin (capabilities.social_share) withdraws the Share entry — justified (enterprise-admin ceiling boundary; data-only catalog row)
  2. Entry hidden until the server answers; empty overflow trigger withdrawn with it — justified
  3. GET /api/dashboard/config gains read-only social_share_enabled; dropped from PUT — justified (extends existing read_only_ignored_keys pattern)
  4. Every evaluation leaves a SEL governance_decision row — justified (the read is the enforcement)
  5. WS slots frame carries governanceGeneration; a withdrawn entry disappears within one 5s tick — justified (an idle focused window otherwise keeps the egress button indefinitely; profile-layer gap declared and tracked)
  6. Mid-compose withdrawal keeps the dialog, disables actions, offers local text salvage — declared; shape is the UX lane's
  7. Mid-export intent click re-reads permission and closes the pre-opened tab — justified (closes the actual egress race, the most cause-level piece)
  8. Security panel names the scope after the menu entry, 13 locales — declared
  9. Capture script + 3 committed PNGs — declared; matches convention (880 files under temp-screenshots/)
  10. Governance spec + feature-map updated in the same commit — mandated by AGENTS.md

Counts run: probe shape matches handlers/mobile_connect.py:44-97 (the named precedent, not a duplicate — it is method-listing-specific); "dashboard:ui" literal appears in 11 places already, so the new constant follows practice; governance_generation() pre-exists (platform/context.py:407); the existing generation watch in ws.py:762-784 is owner-only, so the new dashboard-user watch is not a second spelling.

[FIRST-PRINCIPLES-REVIEWED] 8a9e8a9

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 8a9e8a92c81506ab9c12464725766d470eb701b8 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 8a9e8a9

Verdict parsed from the review's SHA-scoped output markers for commit 8a9e8a92c81506ab9c12464725766d470eb701b8.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 8a9e8a92c81506ab9c12464725766d470eb701b8: <one-sentence reason>

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ human override accepted

Human judgment by @CrysisDeu overrides the GPT 5.6 finding for 8a9e8a92c81506ab9c12464725766d470eb701b8; the recorded reason is authoritative for this commit.

This comment is updated in place on each push.

The model was not re-run because an authorized human decision supersedes it.

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 8a9e8a92c81506ab9c12464725766d470eb701b8: <one-sentence reason>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from b9754a0 to 0b75187 Compare September 4, 2026 22:13
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 0b75187 to 4f8023f Compare September 4, 2026 22:28
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 4f8023f to 455b69b Compare September 4, 2026 23:58
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 455b69b to 146c747 Compare September 5, 2026 00:44
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 5, 2026
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 5, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 146c747 to 8c23281 Compare September 5, 2026 01:41
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 8c23281: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 8c232812187f0bf1c5b307cc9fda543de2d72948.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 8c23281 to 6d70ae2 Compare September 5, 2026 02:06
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 6d70ae2: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 6d70ae254cf2e52acec40230ac6f4328b2e6591a.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 6d70ae2 to ffc0acf Compare September 5, 2026 02:32
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt ffc0acf: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for ffc0acf9bfffe949765f739d7801abe391d78bc1.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from ffc0acf to fc1164b Compare September 5, 2026 02:57
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt fc1164b: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for fc1164ba49880fbfcd0d5e77b571c152ea05cd83.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from fc1164b to b6dc1b3 Compare September 5, 2026 03:15
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt b6dc1b3: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for b6dc1b33e5277f33747984aff89bd9dff6edf446.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from b6dc1b3 to 927d248 Compare September 5, 2026 03:39
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 927d248: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 927d248b07b7b21bb2537e656c8a72fe6fb036f8.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

"Share as image" turns an assistant reply into a branded PNG card and
offers a prefilled post to X / LinkedIn. The card is rendered and
exported in the browser (copy and download never leave the machine), but
the intent buttons hand the caption text to a third-party site in a URL,
so the entry is an egress path for agent output that a managed fleet
must be able to close.

Add a capabilities.social_share SCOPE_CATALOG row (default on, data
only). There is no server-side share action to refuse, so the control is
the dashboard entry: GET /api/dashboard/config reports a read-only
social_share_enabled, evaluated on the pinned dashboard surface through
vet_and_audit (every layer honoured, every decision audited, fail-closed
- the shape the mobile-connect listing uses), and the chat draws the
menu item only when it is true. A menu that would then hold nothing
(loaded window, fork/plan as row buttons) is withdrawn with it. The WS
slots frame carries the governance-ceiling generation so a centrally
pushed policy invalidates the cached answer instead of waiting out its
stale window. The field is dropped from the PUT body so it can never be
written.
@CrysisDeu
CrysisDeu force-pushed the feat/social-share-governance-gate branch from 927d248 to 8a9e8a9 Compare September 5, 2026 03:58
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 8a9e8a9: Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 8a9e8a92c81506ab9c12464725766d470eb701b8.

Profile-layer tightening not bumping governanceGeneration is a deliberate, documented limitation (PR body "Known limitation", follow-up #8623): profiles are operator-local hand-edited files, not the fleet push channel; the policy channel is fully covered; a profile change converges within the 30s staleTime / window focus / next slot mutation — the same contract every other dashboardConfig-derived field (gitlab_hosts, jira_hosts) already has.

This decision applies only to this commit. A new push requires a new judgment.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Sep 5, 2026
@bolichen97
bolichen97 merged commit 5f5e3de into main Sep 5, 2026
65 of 66 checks passed
@bolichen97
bolichen97 deleted the feat/social-share-governance-gate branch September 5, 2026 04:43
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants