Skip to content

V2 admin Data Lifecycle parity and public workspace conversation retention - #1678

Merged
Paul Lizer (paullizer) merged 2 commits into
paullizer-react-v2-uifrom
paullizer-data-lifecycle-admin-parity
Oct 7, 2026
Merged

Paul Lizer (paullizer) merged 2 commits into
paullizer-react-v2-uifrom
paullizer-data-lifecycle-admin-parity

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

In React V2 Admin Settings, the Data Lifecycle group (Retention Policy, Document Classification, Conversation Archiving) only appeared as bare switches from the enable_* fallback scan, with storage keys printed underneath. To set retention periods, change the run hour, run retention, reset owner choices or edit classification categories, admins had to go back to the classic page. This PR declares all three sections in the V2 field schema, adds the V1 controls in V2's design language, and fixes two retention bugs found along the way.

  • Retention Policy:
    • Per-type switches (personal, group, public), with each type's default conversation and document periods nested underneath.
    • A daily run-hour select, saved as an int and shown on the admin's own clock, with a last/next run readout.
    • Inline Run now and Reset to defaults reviews instead of modals. Both offer only the types switched on in saved settings, are disabled while there are unsaved edits, and report per-type counts. They never show raw server exception text.
  • Document Classification and Conversation Archiving: a categories editor (label, color, order) with validation (labels unique regardless of case, length limit, hex color) and a live badge preview. The archiving section now explains its effect, including that retention follows it.
  • Scheduling fix: V2 saves that change a type switch or the run hour now reschedule retention_policy_next_run, as the classic save handler does. Before, switching a type on from V2 left no next run, so retention ran within five minutes instead of at the configured hour. Unrelated saves never move a pending run.
  • Public workspace conversation retention now runs: it was a no-op, and its source referenced containers that do not exist. Chats grounded in a public workspace now follow that workspace's period, the same way group-grounded chats follow their group's. Workspace managers get a count only; each owner is told which of their own chats were removed.
Retention Policy Run now result (dark)
Retention Policy card with per-type switches, nested defaults, run hour and schedule readout Retention card after Run now, with per-type results

Document Classification categories editor with badge preview

Worth a careful look

  • Behaviour change for public-grounded chats:
    • Before, they followed the owner's personal period. Now they follow the public workspace's period while that workspace exists, so with public retention off, retention no longer deletes them.
    • Chats grounded in a public workspace that has since been deleted go back to the owner's personal policy.
    • The personal run lists existing workspaces once. If the listing fails or is cut short, it skips grounded chats for that run instead of treating the failure as "every workspace is gone".
  • Run now / Reset scope: V2 offers only types enabled in saved settings. Classic Manual Execution can run a disabled type, because /api/admin/retention-policy/execute does not check enable flags. The route itself is unchanged.
  • Known limitation, not changed here: chats grounded in a deleted group are excluded from personal retention and no group run reaches them.
  • Version: this branch now includes paullizer-react-v2-ui up to 78d7cef92. The feature is renumbered from 0.261.260 to 0.261.272, because the base had already used 0.261.260 for another change.

Linked issue

N/A, there is no tracking issue for this work.

Release Notes & Latest Features

  • New Feature
  • Bug Fix
  • UI Enhancement
  • Breaking Change
  • Internal only

Is this visible to end users?

  • Yes
  • No

(Through retention behaviour: public workspace owners' conversation periods now take effect, and chat owners are notified about their removed chats. The settings UI itself is admin-only.)

Is this admin-facing (Admin Settings, governance, deployment, config)?

  • Yes
  • No

Should this become a Latest Feature card?

  • Yes
  • No
  • Already added

Screenshot needed for the card?

  • Yes
  • No
  • Attached

Version bump

  • application/single_app/config.py VERSION third segment bumped, or not needed because this is docs-only
  • deployers/version.txt bumped, or not needed because deployers/ was not changed

(0.261.271 on the base -> 0.261.272.)

Testing / validation

All of these ran on the merged head 2a229b244 unless marked otherwise.

  • npm --prefix application/v2_ui run typecheck: passed
  • npm --prefix application/v2_ui run build: passed
  • python -m pytest <every ui_tests/test_v2_admin_*.py suite> -q -p no:cacheprovider: 135 passed, across all 12 V2 admin suites (agents visual hierarchy, data lifecycle, enhanced extraction, file sync, global agents/actions, mixed source, model catalog, operations, search result cache, rail collapse, wide layout, version status). The 13 Data Lifecycle tests cover:
    • real controls instead of fallback switches, and rescheduling on save;
    • held, timeout and server-error states, and per-type results;
    • categories editing and validation;
    • a 390px phone at large text, in light and dark.
  • python functional_tests/test_v2_admin_data_lifecycle_parity.py: 10/10 passed, including 17 TS logic checks.
  • python functional_tests/test_retention_policy_conversation_scope_coverage.py: 7/10 passed.
    • All public-retention tests pass, including the deleted-workspace and failed-listing cases.
    • The 3 collaboration cleanup tests fail the same way on the base, because the harness cannot import functions_orchestration_collaboration, which functions_collaboration now imports.
  • node functional_tests/test_v2_admin_field_visibility.mjs: 22/22 passed.
  • python functional_tests/<file> passed for each of:
    • test_v2_admin_capability_placement.py 9/9, test_v2_admin_field_renderer_coverage.py 4/4, test_v2_admin_section_shell.py 5/5
    • test_v2_admin_settings_normalization.py 15/15, test_v2_admin_schema_vocabulary.py 13/13
    • test_admin_settings_field_contract.py 2/2, test_admin_settings_fields_registry_integrity.py 5/5
    • test_v2_admin_appearance_parity.py 6/6, test_v2_admin_chat_parity.py 7/7, test_v2_admin_workspaces_parity.py 11/11, test_v2_admin_workflow_parity.py 9/9, test_v2_admin_actions_parity.py 10/10, test_v2_admin_agents_parity.py 6/6, test_v2_admin_inbound_mcp_parity.py 9/9
    • test_docs_app_surface_coverage.py 7/7, test_docs_site_quality.py 6/6
  • Failures that also happen on the base, all outside Data Lifecycle:
    • python functional_tests/test_v2_admin_settings_schema.py: 10/11 (m365_trusted_download_hosts default [] is not str).
    • python functional_tests/test_v2_admin_security_parity.py: 7/8 (chat_content_settings_present is unclaimed).
  • python -m pytest functional_tests/test_m365_conversation_lifecycle.py -q -p no:cacheprovider: the 4 in-process tests pass; they drive the real retention module through delete_aged_conversations and a scheduler tick. The subprocess test fails locally because import OpenSSL is broken in this environment.
  • functional_tests/test_group_settings_apis.py and test_public_settings_apis.py could not run locally (before the merge): the Flask test client expects werkzeug.__version__, which the installed Werkzeug lacks. They fail the same way on the base.
  • CI jobs run locally on 78d7cef92...2a229b244:
    • python -m py_compile over application/single_app/*.py: 0 failures.
    • python scripts/check_xss_sinks.py --base-sha <base> --head-sha <head> <11 changed app files>: passed.
    • python scripts/check_broken_access_control.py --base-sha <base> --head-sha <head> <3 changed .py files>: passed.
    • python scripts/check_malicious_pr_security_review.py --base-sha <base> --head-sha <head> --verify-release-age: no blocker findings (advisory warnings only).
  • Mutation checks (before the merge; the feature code is unchanged since): the new tests catch each of these deliberate breakages:
    • excluding every grounded chat (the old rule);
    • reading a failed listing as an empty set;
    • dropping the listing from the personal run;
    • making V2 rescheduling a no-op.
  • Manual: I reviewed all three cards at 1440px and at 390px with large text, in light and dark (screenshots above).

Documentation

  • Release notes updated, or not needed
  • Feature documentation updated, or not needed
  • Fix documentation updated, or not needed

(Release notes are not added yet; they go under 0.261.272. Docs updated: docs/admin/data-lifecycle.md, docs/explanation/features/V2_ADMIN_DATA_LIFECYCLE_SETTINGS.md, docs/explanation/features/REACT_V2_UI.md, docs/explanation/fixes/PUBLIC_WORKSPACE_CONVERSATION_RETENTION_FIX.md.)

Security checklist

  • New Flask routes include @swagger_route(security=get_auth_security()) (no new routes)
  • Settings sent to non-admin frontends use sanitize_settings_for_user() (admin-only surface; no non-admin settings payloads changed)
  • Browser JavaScript is served from local SimpleChat static assets only; no CDN-hosted JS
  • No secrets, keys, connection strings, or local-only artifacts are included

Paul Lizer (paullizer) and others added 2 commits October 6, 2026 22:21
The React V2 Admin Settings drew Retention Policy, Document Classification and
Conversation Archiving through the enable_* fallback, as bare switches with their
storage keys printed beneath them. Describe all three sections in the V2 field
schema and add the controls V1 offers:

- Per-type retention switches with nested conversation/document defaults, a run
  hour select that saves an int, and a last/next run readout
- Inline Run now and Reset to defaults reviews, limited to types switched on in
  saved settings and held while edits are unsaved; results show per-type counts
  and never raw server exception text
- A document classification categories editor with validation and badge preview
- Reschedule the next retention run when a V2 save changes a scope switch or the
  run hour, matching the classic save handler

Make public workspace conversation retention functional. Chats grounded in a
public workspace follow that workspace's policy while it exists and return to
their owner's personal policy once it is deleted; a failed workspace listing
skips grounded chats for that run. Workspace managers get a count, and each
owner is told which of their own chats were removed.

Add parity, logic and Playwright coverage, admin/feature/fix docs, and bump the
version to 0.261.260.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The base moved 58 commits ahead (now 0.261.271) and had already used 0.261.260
for another change, so this feature is renumbered to 0.261.272 in config.py,
test headers and docs. The target's own 0.261.260 reference is untouched.

Conflicts were all "both sides added" and keep both:
- config.py: VERSION 0.261.272
- admin_settings_fields.py: on_enable docs plus Data Lifecycle and Operations in
  the described-groups list; both LEGACY_FIELD_NAMES entries; operations
  derivations and the retention schedule both run on valid saves
- AdminSettingsPage.tsx: target imports plus the Retention imports (stale
  delegation imports dropped, as on the target); mergeStoredSettings alongside
  the target's helpers; Retention/classification and Operations case branches
- test_v2_admin_capability_placement.py: workspaces, data-lifecycle, operations
- test_v2_admin_section_logic.ts: combined header history

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit 3834690 into paullizer-react-v2-ui Oct 7, 2026
11 checks passed
Paul Lizer (paullizer) added a commit that referenced this pull request Oct 7, 2026
…61.273

Brings in the base through the data-lifecycle parity merge and resolves the
nine conflicts by keeping both sides:

- admin_settings_fields.py: Help declarations, validators and legacy maps sit
  beside the new Data Lifecycle, Operations and on_enable work. Health Check
  now lives with Operations, as the base moved it.
- related_section: the base shipped the same descriptor as
  {section_id, label, classic_only}, drawn by RelatedSectionLink.tsx. The
  Latest Features destination now uses that shape and renderer, and the
  duplicate {id, label} link and onNavigate plumbing in fields.tsx and
  adminFields.ts are removed. The schema test accepts the base's shape.
- SettingsSection.tsx: the header badge joins the guide button and status
  chip; the status context wraps the base's new grouped body.
- fields.tsx: the Required flag reads the section status before the
  timezone branch, so the hook runs on every render.
- AdminSettingsPage.tsx: catalogue fetch, search and Help cases sit beside
  the section guides, retention and operations cases. In the collapsible
  rail the Help New pill becomes a dot, keeping "New" in the accessible name.
- Tests and fixture headers keep both histories. FULLY_DESCRIBED_GROUP_IDS
  now includes data-lifecycle, operations and help.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.

1 participant