142 lines
11 KiB
Markdown
142 lines
11 KiB
Markdown
# Research — Private AI Execution & Policy Foundation
|
|
|
|
**Date**: 2026-04-27
|
|
**Spec**: [spec.md](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](../../apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php) page, with validation registered through [SettingsRegistry](../../apps/platform/app/Support/Settings/SettingsRegistry.php) and persistence/audit handled by [SettingsWriter](../../apps/platform/app/Services/Settings/SettingsWriter.php).
|
|
|
|
**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](../../apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php) already owns the `/admin/settings/workspace` singleton route and uses `Capabilities::WORKSPACE_SETTINGS_VIEW` / `Capabilities::WORKSPACE_SETTINGS_MANAGE`.
|
|
- [SettingsRegistry](../../apps/platform/app/Support/Settings/SettingsRegistry.php) is the canonical place for setting definitions and validation.
|
|
- [SettingsWriter](../../apps/platform/app/Services/Settings/SettingsWriter.php) 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](../../apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php), evaluate it through [OperationalControlEvaluator](../../apps/platform/app/Support/OperationalControls/OperationalControlEvaluator.php), and expose it only on the existing [Controls](../../apps/platform/app/Filament/System/Pages/Ops/Controls.php) 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**:
|
|
- [Controls](../../apps/platform/app/Filament/System/Pages/Ops/Controls.php) already owns confirmation-protected pause/resume actions and history for operational controls.
|
|
- [OperationalControlCatalog](../../apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php) is the existing source of control keys, labels, and supported scopes.
|
|
- [OperationalControlEvaluator](../../apps/platform/app/Support/OperationalControls/OperationalControlEvaluator.php) is the existing runtime lookup path.
|
|
- [SystemPanelProvider](../../apps/platform/app/Providers/Filament/SystemPanelProvider.php) and [PlatformCapabilities](../../apps/platform/app/Support/Auth/PlatformCapabilities.php) already enforce the `/system` plane and `platform.ops.controls.manage` capability.
|
|
|
|
**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:
|
|
|
|
- `product_knowledge.answer_draft`, anchored to [ContextualHelpResolver](../../apps/platform/app/Support/ProductKnowledge/ContextualHelpResolver.php) and its code-owned knowledge source
|
|
- `support_diagnostics.summary_draft`, anchored to [SupportDiagnosticBundleBuilder](../../apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php) as a derived summary path
|
|
|
|
**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**:
|
|
- [ContextualHelpResolver](../../apps/platform/app/Support/ProductKnowledge/ContextualHelpResolver.php) already exposes `knowledgeSource()` for code-owned product knowledge.
|
|
- [SupportDiagnosticBundleBuilder](../../apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php) already produces the diagnostics data family used from the tenant dashboard and the tenantless operation viewer.
|
|
|
|
**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](../../apps/platform/app/Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php) 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](../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php) and the underlying [AuditActionId](../../apps/platform/app/Support/Audit/AuditActionId.php) / `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**:
|
|
- [SettingsWriter](../../apps/platform/app/Services/Settings/SettingsWriter.php) already logs workspace-setting updates and resets.
|
|
- [WorkspaceAuditLogger](../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php) already records workspace-scoped and tenant-scoped audit entries.
|
|
- [AuditActionId](../../apps/platform/app/Support/Audit/AuditActionId.php) is the canonical action registry.
|
|
|
|
**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. |