TenantAtlas/specs/248-private-ai-policy-foundation/research.md
ahmido ff3392892b
Some checks failed
Main Confidence / confidence (push) Failing after 56s
Merge 248-private-ai-policy-foundation into dev (#288)
Automated PR: merge branch 248-private-ai-policy-foundation into dev (created by Copilot)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #288
2026-04-27 21:18:37 +00:00

11 KiB

Research — Private AI Execution & Policy Foundation

Date: 2026-04-27
Spec: spec.md

This document resolves planning unknowns and records the repo-backed decisions that keep Spec 248 narrow.

Decision 1 — Reuse workspace settings for AI policy truth

Decision: Store workspace AI posture as a workspace setting at ai.policy_mode on the existing WorkspaceSettings page, with validation registered through SettingsRegistry and persistence/audit handled by SettingsWriter.

Rationale:

  • The repo already has a singleton workspace settings surface, a central settings registry, and an audited writer path.
  • Reusing that stack preserves workspace ownership and avoids inventing a second admin surface or a new AI persistence table.
  • The existing workspace settings capabilities already separate view and manage permissions.

Evidence:

  • WorkspaceSettings already owns the /admin/settings/workspace singleton route and uses Capabilities::WORKSPACE_SETTINGS_VIEW / Capabilities::WORKSPACE_SETTINGS_MANAGE.
  • SettingsRegistry is the canonical place for setting definitions and validation.
  • SettingsWriter already persists workspace settings and records workspace_setting.updated / workspace_setting.reset audit events.

Alternatives considered:

  • Add a dedicated workspace_ai_policies table.
    • Rejected: new persisted truth is unnecessary for a single workspace-owned mode and would violate the narrow v1 scope.
  • Hide AI posture in environment config or feature flags.
    • Rejected: not workspace-owned, not operator-auditable, and not compatible with the product requirement for explicit workspace policy.

Decision 2 — Reuse the existing operational-controls path for the runtime stop

Decision: Add ai.execution to OperationalControlCatalog, evaluate it through OperationalControlEvaluator, and expose it only on the existing Controls page under the current /system panel.

Rationale:

  • The repo already has a platform-only control-center pattern with confirmation, scope previews, and audit logging.
  • Reusing it avoids a second AI-specific emergency-stop mechanism or a new system AI console.
  • The platform plane auth guard and capability checks are already in place for this page.

Evidence:

Alternatives considered:

  • Add an AI-specific console or admin page under /system.
    • Rejected: duplicates the existing ops-controls pattern and broadens v1 without adding new product truth.
  • Use a deploy-time environment flag as the emergency stop.
    • Rejected: not operator-owned, not auditable, and not aligned with the current control-center workflow.

Decision 3 — Treat v1 as a governed decision boundary, not an AI provider runtime

Decision: The new AI seam should be an in-process governed decision boundary that accepts a registered use-case request and returns an allow/block decision plus audit-ready metadata. It must not include provider adapters, outbound model execution, queue orchestration, or result persistence in this slice.

Rationale:

  • The spec explicitly avoids direct external provider calls with tenant data, OperationRun semantics, result persistence, and a broad marketplace.
  • The repo has no existing AI execution layer, so the smallest safe first step is the allow/block contract itself.
  • A decision-first seam is enough to stop local provider calls from appearing feature by feature.

Evidence:

  • There is no app-level AI support namespace in apps/platform/app/** today.
  • Existing shared seams cover settings, ops controls, audit, product knowledge, and support diagnostics, but none of them own AI allow/block semantics.

Alternatives considered:

  • Add feature-local AI helpers in product knowledge and diagnostics first.
    • Rejected: duplicates policy, provider-class, and data-classification rules across surfaces.
  • Build a full provider abstraction layer now.
    • Rejected: speculative architecture before the first concrete provider runtime is even in scope.

Decision 4 — Lock v1 to two approved internal-only use cases and derive them from existing seams

Decision: Keep the v1 catalog locked to exactly two use cases:

Rationale:

  • These are the two named likely adopters from the spec and both already exist as internal-only seams.
  • Limiting the catalog to two concrete consumers satisfies ABSTR-001 while still proving the shared decision vocabulary is reusable.
  • Open-ended catalog growth would silently widen scope into a general AI platform.

Evidence:

Alternatives considered:

  • Allow any caller to register arbitrary AI use cases at runtime.
    • Rejected: creates speculative platform scope and weakens governance.
  • Ship only one adopter in v1.
    • Rejected: the safety justification for the central catalog is stronger with the two real future consumers already identified by the spec.

Decision 5 — Support diagnostics input must be a derived redacted summary, not the raw bundle

Decision: support_diagnostics.summary_draft should consume a derived redacted summary of the support-diagnostics bundle, not the raw sections array or the raw provider/context payloads already present in the bundle structure.

Rationale:

  • The current support-diagnostics bundle is broad, structured, and designed for operator inspection, not AI transport.
  • Passing the raw bundle would violate the explicit v1 ban on raw provider payloads, customer-confidential data, and raw evidence excerpts.
  • A derived summary keeps the AI boundary honest: if the summary cannot be produced safely, the use case should stay blocked.

Evidence:

  • SupportDiagnosticBundleBuilder currently produces a rich sections structure plus contextual help and redaction notes, not a purpose-built AI summary.

Alternatives considered:

  • Feed the full support-diagnostics bundle into AI with field-level filtering.
    • Rejected: still too broad for v1, easier to get wrong, and unnecessary for the first governed foundation slice.

Decision 6 — Reuse the existing audit pipeline and keep the AI audit family minimal

Decision: Reuse WorkspaceAuditLogger and the underlying AuditActionId / AuditRecorder path. Keep workspace policy mutations on the existing workspace_setting.updated / workspace_setting.reset actions and add one bounded AI decision action ID for governed decision evaluations with structured metadata only.

Rationale:

  • Policy changes already flow through the workspace settings audit path and should not create a second mutation pattern.
  • AI decision evaluations need a stable audit record, but the narrowest shape is one action ID plus metadata, not a full AI run ledger.
  • The spec explicitly bans raw prompt, raw source payload, and output persistence.

Evidence:

Alternatives considered:

  • Add a dedicated AI audit table or prompt history store.
    • Rejected: violates the v1 no-new-persistence constraint and imports a second source of truth.
  • Split AI decisions into many action IDs (allowed, blocked, control_blocked, etc.).
    • Rejected for v1: one bounded decision action plus metadata is the smaller audit family.

Decision 7 — Keep proof narrow: unit + feature + architecture guard

Decision: Prove the slice with narrow unit tests for the decision matrix, focused feature tests for the two existing operator surfaces, and one architecture guard that fails if direct AI-provider access appears outside the governed boundary.

Rationale:

  • Unit coverage is the cheapest place to prove the allow/block matrix.
  • Feature coverage is still needed because the slice touches the existing workspace settings and system controls surfaces.
  • Browser and heavy-governance workflows would add cost without proving additional v1 truth.

Evidence:

  • Existing settings and operational-controls tests already show the repo prefers focused Pest feature tests plus targeted unit tests over browser coverage for this class of work.

Alternatives considered:

  • Add browser smoke coverage in v1.
    • Rejected: unnecessary for the narrow foundation slice and not the cheapest proof.
  • Reuse the broad WorkspaceSettingsManageTest.php family as the primary proof.
    • Rejected: it is workflow-heavy and should not become the default proving lane for a narrow AI policy field.