Automated PR provided by Codex via Gitea API. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #482
20 KiB
Implementation Plan: Spec 415 - Generic Content-Backed Capture
Branch: 415-generic-content-backed-capture | Date: 2026-06-25 | Spec: specs/415-generic-content-backed-capture/spec.md
Input: Feature specification from /specs/415-generic-content-backed-capture/spec.md
Summary
Prepare Coverage v2 to store real content-backed evidence without activating it as customer/operator truth. The implementation should add concrete Coverage v2 resource and evidence persistence, resolve source contracts through the existing registry/Graph contract path, capture eligible payloads through GraphClientInterface, normalize/hash/redact payloads, and run remote capture through an authorized, queued, OperationRun-backed service.
The slice is intentionally backend/internal. No Filament page, route, navigation entry, customer output, review/report surface, restore readiness surface, or browser-visible v2 coverage claim is added.
Technical Context
Language/Version: PHP 8.4.15, Laravel 12.52.0
Primary Dependencies: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Sail 1.52.0
Storage: PostgreSQL; JSONB for raw payload, normalized payload, permission/source metadata
Testing: Pest 4; unit, feature, and PostgreSQL lanes where database constraints/indexes require PostgreSQL proof
Validation Lanes: fast-feedback, confidence, pgsql; browser N/A unless UI scope is amended
Target Platform: Laravel monolith in apps/platform, Sail local, Dokploy container staging/production
Project Type: web application backend/runtime slice
Performance Goals: render-time remains DB-only/no Graph; remote capture queued; indexes limited to known query paths
Constraints: no UI activation, no direct Graph calls, no endpoint guessing, no tenant_id, no compatibility shim, no raw payload leakage, OperationRun lifecycle service-owned
Scale/Scope: initial Spec 414 resource types only; no full TCM catalog, compare/render/restore, or legacy removal
Existing Repo Truth
- Spec 414 completed the inactive Coverage v2 kernel and contains implementation close-out evidence.
- Existing Coverage v2 kernel files include:
apps/platform/app/Models/TenantConfigurationResourceType.phpapps/platform/app/Models/TenantConfigurationSupportedScope.phpapps/platform/app/Services/TenantConfiguration/ResourceTypeRegistry.phpapps/platform/app/Services/TenantConfiguration/SupportedScopeResolver.phpapps/platform/app/Services/TenantConfiguration/ClaimGuard.phpapps/platform/app/Support/TenantConfiguration/*apps/platform/database/migrations/2026_06_25_000414_create_tenant_configuration_kernel_tables.php
- Spec 414 deferred
tenant_configuration_resourcesandtenant_configuration_resource_evidence. OperationRunTypedoes not yet containtenant_configuration.capture.OperationSummaryKeys::all()does not currently containcapturedorblocked; Spec 415 should use existing numeric keys unless it explicitly extends the canonical list with tests.config/graph_contracts.phpcontains contract entries relevant tonotificationMessageTemplate,roleScopeTag, andassignmentFilter. TCM-aligned source eligibility must still be explicit; missing contracts must block capture.Capabilities::EVIDENCE_MANAGEexists and is granted to Manager/Owner but not Operator/Readonly. It is the default planned capability unless implementation finds a more specific existing capture capability.
UI / Surface Guardrail Plan
- Guardrail scope: no operator-facing surface change.
- Affected routes/pages/actions/states/navigation/panel/provider surfaces: N/A.
- No-impact class, if applicable: backend-only internal evidence capture. Existing generic Monitoring -> Operations and central DB-notification surfaces may show OperationRun records through the shared lifecycle contract; no feature-local UI, notification copy, links, or rendered controls are added.
- Native vs custom classification summary: N/A.
- Shared-family relevance: OperationRun lifecycle and Graph service boundary only.
- State layers in scope: none.
- Audience modes in scope: N/A.
- Decision/diagnostic/raw hierarchy plan: raw payloads remain evidence-storage only; no default UI exposure.
- Raw/support gating plan: no rendered access path in this spec.
- One-primary-action / duplicate-truth control: no UI action introduced; no v2 customer/operator truth.
- Handling modes by drift class or surface: hard-stop if UI files/routes/navigation/customer output are touched without spec/plan/tasks amendment.
- Repository-signal treatment: review-mandatory for any UI file change, route addition, new Filament resource, or customer/report/review/evidence activation.
- Special surface test profiles: N/A.
- Required tests or manual smoke: functional-core, persistence, RBAC, OperationRun, no-UI static guards.
- Exception path and spread control: none.
- Active feature PR close-out entry: Guardrail / N/A no rendered UI surface changed.
- UI/Productization coverage decision: No UI surface impact.
- Coverage artifacts to update: none.
- No-impact rationale: backend-only internal capture path; no reachable UI surface changed.
- Navigation / Filament provider-panel handling: no panel/provider change.
- Screenshot or page-report need: no.
Product Surface Contract Plan
- Product Surface Contract reference:
docs/product/standards/product-surface-contract.md. - No-legacy posture: canonical v2 evidence path; no compatibility exception.
- Page archetype and surface budget plan: N/A - no rendered product surface changed.
- Technical Annex and deep-link demotion plan: no default product view exposes OperationRun, raw evidence IDs, source keys, payloads, fingerprints, or logs.
- Canonical status vocabulary plan: N/A - no product-facing status labels.
- Product Surface exceptions: none.
- Browser verification plan:
N/A - no rendered UI surface changed; existing generic OperationRun surfaces are not customized by this spec. - Human Product Sanity plan: N/A - no rendered product surface changed.
- Visible complexity outcome target: neutral for rendered UI.
- Implementation report target:
specs/415-generic-content-backed-capture/implementation-report.md.
Filament / Livewire / Deployment Posture
- Livewire v4 compliance: Livewire v4.1.4 confirmed; no Livewire UI code planned.
- Panel provider registration location: no panel change; Laravel 12 panel providers remain in
apps/platform/bootstrap/providers.php. - Global search posture: no Filament Resource is added. If implementation accidentally adds a resource, stop and amend artifacts before continuing; resource must disable global search or provide safe View/Edit page and
$recordTitleAttribute. - Destructive/high-impact action posture: no rendered action. Capture start is high-impact remote/provider work and must authorize server-side, create/reuse OperationRun, audit safely, queue work, and avoid raw payloads.
- Asset strategy: no assets, no
filament:assetsdeployment requirement from this spec. - Testing plan: unit tests for resolver/normalizer/hash/redaction/outcomes; feature/pgsql tests for persistence, RBAC, provider scope, fake Graph, OperationRun, and no-legacy guards.
- Deployment impact: database migrations and queue workers expected; no env vars, scheduler, storage volume, routes, assets, or reverse proxy changes expected unless implementation discovers a repo-real need and amends artifacts.
Shared Pattern & System Fit
- Cross-cutting feature marker: yes.
- Systems touched: Coverage v2 kernel, OperationRun, Graph contracts/client, capability registry, audit recorder, queue/job infrastructure.
- Shared abstractions reused:
ResourceTypeRegistry,SupportedScopeResolver,ClaimGuard,GraphClientInterface,GraphContractRegistry,OperationRunService,OperationSummaryKeys,Capabilities,RoleCapabilityMap. - New abstraction introduced? why?: bounded capture-specific services are introduced because registry-only Coverage v2 cannot persist content evidence, normalize/hash payloads, or produce safe per-type outcomes.
- Why the existing abstraction was sufficient or insufficient: existing kernel services classify resource types and claims but do not fetch, normalize, or persist payload evidence. Existing OperationRun and Graph seams are sufficient and must be reused.
- Bounded deviation / spread control: no new provider framework, no UI framework, no generic identity engine, no compare/render/restore pipeline.
OperationRun UX Impact
- Touches OperationRun start/completion/link UX?: backend lifecycle yes; rendered UX no.
- Central contract reused: OperationRun lifecycle via
OperationRunService; if a start surface appears, central OperationRun Start UX Contract is mandatory and artifacts must be amended first. - Delegated UX behaviors: no local toast/link/event planned; terminal notifications remain lifecycle-owned through the existing generic OperationRun path.
- Surface-owned behavior kept local: initiation inputs only in an internal service/action.
- Queued DB-notification policy: no queued DB notifications.
- Terminal notification path: central lifecycle mechanism.
- Exception path: none.
Provider Boundary & Portability Fit
- Shared provider/platform boundary touched?: yes.
- Provider-owned seams: TCM source class, Graph v1 fallback source class, Graph beta experimental source class, provider-specific Graph contract metadata, permission/source context.
- Platform-core seams: concrete Coverage v2 resource/evidence ownership, capture outcome vocabulary, OperationRun execution truth, evidence payload truth.
- Neutral platform terms / contracts preserved: provider, source contract, operation, evidence, resource, managed environment, capture outcome.
- Retained provider-specific semantics and why: Spec 414 source classes remain because this is a TCM-first Microsoft coverage path.
- Bounded extraction or follow-up path: Spec 416 Canonical Identity Engine after payload-backed evidence exists.
Constitution Check
- Inventory-first / snapshots-second: PASS. This spec creates explicit evidence capture, not UI claim truth or snapshot replacement.
- Read/write separation: PASS with controls. Capture writes internal evidence and must be authorized, audited, queued, and OperationRun-backed.
- Single Graph contract path: PASS. Graph calls must go through
GraphClientInterfaceand repo contract registry. - Deterministic capabilities: PASS. Authorization uses canonical capability constants; default planned capability is
EVIDENCE_MANAGE. - RBAC-UX: PASS. Non-member/not entitled is 404; member missing capability is 403; server-side Gate/Policy required.
- Workspace isolation: PASS.
workspace_id+managed_environment_idare required for environment-owned records. - Tenant isolation: PASS in current terminology. No
tenant_idownership column is introduced. - Provider boundary: PASS. Provider-native IDs stay metadata; provider connection must be same workspace/environment.
- OperationRun observability: PASS. Remote/provider capture uses OperationRun and queue.
- OperationRun lifecycle: PASS. Transitions must use
OperationRunService. - Summary counts: PASS with constraint. Use
OperationSummaryKeys::all(); default existing keys avoid new summary-key family. - Test governance: PASS. Unit/feature/pgsql lanes are named; browser/heavy-governance are N/A.
- Proportionality: PASS with justified complexity. New persistence and services are needed for audit/evidence/source-of-truth correctness.
- No premature abstraction: PASS with bounded exception. Capture services are specific to current Coverage v2 evidence needs and initial resource types.
- Persisted truth: PASS. Evidence rows are durable append-only proof with independent lifecycle.
- Behavioral state: PASS. Capture outcomes affect persistence, run summaries, retry/failure handling, and reviewer gates.
- UI semantics: PASS. No UI framework or rendered status taxonomy.
- Product Surface Contract: PASS. No rendered UI surface changed.
- LEAN-001: PASS. No aliases, dual writes, fallback readers, compatibility shims, or legacy fixtures.
Test Governance Check
- Test purpose / classification by changed surface: Unit for pure capture helpers; Feature/PostgreSQL for persistence, RBAC, OperationRun, Graph fake, provider-scope constraints, no-legacy guards.
- Affected validation lanes: fast-feedback, confidence, pgsql.
- Why this lane mix is the narrowest sufficient proof: no rendered UI exists; backend behavior and persistence are the risk.
- Narrowest proving command(s):
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfigurationcd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfigurationcd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml tests/Feature/TenantConfigurationwhen PostgreSQL-only constraints/indexes are added
- Fixture / helper / factory / seed / context cost risks: managed-environment/provider-connection/Graph fake setup must remain explicit and local.
- Expensive defaults or shared helper growth introduced?: no; any helper must be opt-in.
- Heavy-family additions, promotions, or visibility changes: none.
- Surface-class relief / special coverage rule: N/A no rendered UI.
- Closing validation and reviewer handoff: verify no UI activation, no real Graph calls, no
tenant_id, no old v1 vocabulary, same-scope provider connection, sanitized contexts, OperationRunService lifecycle. - Budget / baseline / trend follow-up: none expected.
- Review-stop questions: lane fit, hidden Graph call risk, fixture breadth, OperationRun summary keys, provider-scope constraints.
- Escalation path: document-in-feature for local helper cost; follow-up-spec only for identity engine or UI activation.
- Active feature PR close-out entry: Guardrail / no rendered UI.
- Why no dedicated follow-up spec is needed: the runtime capture foundation is the current feature; identity/UI/cutover are already deferred follow-ups.
Project Structure
Documentation (this feature)
specs/415-generic-content-backed-capture/
├── spec.md
├── plan.md
├── tasks.md
├── checklists/
│ └── requirements.md
└── implementation-report.md
Source Code (likely affected in later implementation)
apps/platform/app/Models/
├── TenantConfigurationResource.php
└── TenantConfigurationResourceEvidence.php
apps/platform/app/Services/TenantConfiguration/
├── CoverageSourceContractResolver.php
├── GenericPayloadNormalizer.php
├── CoverageResourceUpserter.php
├── CoverageEvidenceWriter.php
├── GenericContentEvidenceCaptureService.php
├── StartTenantConfigurationCapture.php
└── CoverageCaptureOutcomeSummarizer.php
apps/platform/app/Support/TenantConfiguration/
└── CaptureOutcome.php
apps/platform/app/Jobs/TenantConfiguration/
└── CaptureTenantConfigurationEvidenceJob.php
apps/platform/database/migrations/
└── *_create_tenant_configuration_capture_tables.php
apps/platform/database/factories/
├── TenantConfigurationResourceFactory.php
└── TenantConfigurationResourceEvidenceFactory.php
apps/platform/tests/Unit/Support/TenantConfiguration/
└── Spec415*Test.php
apps/platform/tests/Feature/TenantConfiguration/
└── Spec415*Test.php
Structure Decision: Use the existing apps/platform Laravel monolith. Keep capture domain code under the existing Services/TenantConfiguration and Support/TenantConfiguration namespaces. Add jobs under a tenant-configuration job namespace only if the repo does not already have a closer convention.
Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| New resource/evidence tables | Durable append-only v2 evidence needs independent lifecycle and auditability | v1 snapshots or metadata-only rows would create hidden dual truth |
| New capture services | Fetch/normalize/hash/redact/persist responsibilities must stay out of Filament, models, and jobs | Putting workflow in a job or model would make authorization/audit/Graph seams harder to test |
| New capture outcome family | Implementation must distinguish missing contract, permission, beta, unsupported, captured, and failed because each has different persistence/run behavior | Reusing old gap taxonomy is explicitly forbidden and misleading |
Proportionality Review
- Current operator problem: future Coverage v2 operator/customer claims require concrete evidence proof; otherwise the product can overclaim coverage based on registry truth only.
- Existing structure is insufficient because: Spec 414 has registry/scope/claim guard only, while v1 runtime evidence cannot safely stand in for v2 proof.
- Narrowest correct implementation: initial 414 resource types, contract-driven eligibility, append-only evidence, generic normalization/hash, redaction, OperationRun-backed async execution, no UI.
- Ownership cost created: migrations/models/services/job/tests and ongoing care around redaction, queue behavior, and provider contract mapping.
- Alternative intentionally rejected: v1 snapshot promotion, metadata-only capture, UI activation, broad TCM catalog import, semantic compare/render/restore.
- Release truth: current-release foundation after completed Spec 414.
Implementation Phases
Phase 0 - Preflight
- Confirm branch, HEAD, clean/dirty state.
- Confirm Spec 414 implementation report and completed tasks remain read-only context.
- Confirm no existing
tenant_configuration_resources/tenant_configuration_resource_evidenceequivalent exists. - Confirm graph contract entries and 414 registry metadata for initial resource types.
Phase 1 - Tests First
- Add unit tests for resolver, normalizer, hash, redaction, and capture outcome behavior.
- Add feature/PostgreSQL tests for persistence, JSONB, same-scope provider connection, RBAC, OperationRun, fake Graph, and no-legacy/no-UI guards.
Phase 2 - Persistence
- Add concrete resource and evidence tables/models/factories if missing.
- Enforce
workspace_id,managed_environment_id, same-scopeprovider_connection_id, notenant_id, append-only evidence, and targeted indexes.
Phase 3 - Source Resolution And Normalization
- Resolve source contracts from Coverage v2 registry and repo Graph contract registry.
- Block missing/beta/unsupported sources safely.
- Normalize payloads minimally, hash deterministically, and redact permission/source context.
Phase 4 - OperationRun Start And Queue
- Add
tenant_configuration.captureOperationRun type/catalog entry if required by repo conventions. - Implement authorized internal start service/action.
- Queue remote capture job and keep lifecycle transitions in
OperationRunService. - Use existing
OperationSummaryKeysunless a tested canonical extension is required.
Phase 5 - Capture And Evidence Write
- Fetch via
GraphClientInterfacefakeable calls only where explicit contracts exist. - Upsert concrete resource rows by deterministic identity.
- Write append-only evidence rows and per-type outcomes.
- Audit start/completion/failure safely through the existing
AuditRecorder/AuditEventBuilderpath with stabletenant_configuration.capture.started,tenant_configuration.capture.completed, andtenant_configuration.capture.failedaction IDs.
Phase 6 - Report And Validation
- Complete implementation report with eligibility matrix and safety proof.
- Run focused Pint/tests/pgsql lane as needed and
git diff --check. - Record no-browser, no-assets, no-global-search, no-Filament-provider-change, and deployment impact.
Stop Conditions
- Spec 414 kernel is missing or not accepted.
- Implementation needs customer/operator UI activation.
- Implementation needs v1 adapter, dual-write, fallback reader, old snapshot promotion, or old gap taxonomy.
- Implementation needs hardcoded Graph endpoints or direct HTTP/SDK calls outside
GraphClientInterface. - Implementation needs beta capture opt-in.
- Implementation needs broad identity engine, semantic compare, rendering, restore/apply, or full catalog import.
- Implementation changes rendered UI files, routes, navigation, reports, downloads, or evidence/review surfaces without amending spec/plan/tasks first.