Automated PR provided by Codex via Gitea API. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #482
370 lines
36 KiB
Markdown
370 lines
36 KiB
Markdown
# Feature Specification: Spec 415 - Generic Content-Backed Capture
|
|
|
|
**Feature Branch**: `415-generic-content-backed-capture`
|
|
**Created**: 2026-06-25
|
|
**Status**: Draft
|
|
**Input**: User-provided candidate "415 - Generic Content-Backed Capture" as the next bounded follow-up after Spec 414.
|
|
|
|
## Candidate Selection Summary
|
|
|
|
- **Selected candidate**: Spec 415 - Generic Content-Backed Capture.
|
|
- **Source**: Direct user-provided candidate in `/Users/ahmeddarrazi/.codex/attachments/b061549c-2e15-4bb3-b5ab-a2c3e23d0d55/pasted-text.txt`.
|
|
- **Why selected**: Spec 414 is implemented as an inactive Coverage v2 kernel and explicitly defers OperationRun-backed content-backed capture. This spec is the next narrow foundation slice: store real v2 payload evidence without activating v2 as customer-facing truth.
|
|
- **Roadmap relationship**: Supports evidence/coverage hardening, provider-boundary discipline, OperationRun observability, and future Coverage v2 activation. It does not create a new product surface.
|
|
- **Close alternatives deferred**: `docs/product/spec-candidates.md` currently has no safe automatic next-best-prep target. Manual backlog items require explicit product promotion. Spec 416 Canonical Identity Engine is deferred until v2 can persist payload-backed evidence.
|
|
- **Related completed-spec guardrail**: `specs/414-tcm-first-coverage-core-cutover/` is completed and validated. It is dependency context only and must not be rewritten. No existing `415-*` spec or branch was found before creation.
|
|
- **Smallest viable implementation slice**: Add internal, OperationRun-backed, contract-driven capture for the Spec 414 initial resource types, with concrete resource/evidence persistence, deterministic normalization/hashing, redaction, RBAC/scope guards, and no rendered UI activation.
|
|
|
|
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
|
|
|
- **Problem**: Coverage v2 can classify resource types after Spec 414, but it still cannot persist concrete, content-backed evidence for resources in a managed environment.
|
|
- **Today's failure**: Later activation would risk registry-only claims, metadata-only proof, hidden reliance on v1 snapshots, or future compare/render work without durable v2 payload truth.
|
|
- **User-visible improvement**: No immediate UI change. The trust improvement is that future customer/operator coverage claims can be grounded in append-only v2 evidence instead of registry assertions.
|
|
- **Smallest enterprise-capable version**: Persist concrete v2 resources and append-only evidence for the initial 414 resource types, capture only where explicit repo contracts exist, block unsafe/missing/beta contracts, and summarize execution through OperationRun.
|
|
- **Explicit non-goals**: No Coverage v2 UI activation, no Evidence Overview/Review Workspace/Review Pack/Report/Restore/Compare conversion, no v1-to-v2 adapter, no full TCM catalog import, no semantic diff, no rendering, no restore/apply, no browser-visible UI.
|
|
- **Permanent complexity imported**: New environment-owned resource/evidence tables and models, a bounded capture outcome family, capture/source/normalization/redaction services, an OperationRun type, job/start service, authorization tests, and focused guard tests.
|
|
- **Why now**: Spec 414 completed the inactive kernel and named generic content-backed capture as the next dependency. Payload evidence is a prerequisite for identity hardening, operator surface activation, compare/render packs, certification, and legacy removal.
|
|
- **Why not local**: Reusing v1 snapshots or adding a local metadata helper would keep dual truth and would not prove provider-connection ownership, payload redaction, Graph contract discipline, or OperationRun execution truth.
|
|
- **Approval class**: Core Enterprise.
|
|
- **Red flags triggered**: New persisted truth, new service abstractions, new outcome/status-like family, foundation terminology. Defense: the slice is bounded to real current dependency value, no UI activation, no compatibility layer, initial 414 resource types only, and security/audit/queue correctness justify the added structure.
|
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | **Gesamt: 10/12**
|
|
- **Decision**: approve as a bounded preparation package.
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: tenant / managed-environment operational evidence under workspace ownership.
|
|
- **Primary Routes**: N/A - no route or rendered UI surface is added or changed.
|
|
- **Data Ownership**: Environment-owned capture records use `workspace_id` + `managed_environment_id`; provider-sourced records include `provider_connection_id`. Provider-native tenant/directory/account IDs remain metadata only.
|
|
- **RBAC**: Workspace membership and managed-environment entitlement are required. Missing membership/entitlement returns 404. Established members without the capture capability return 403. Server-side Gate/Policy enforcement is required on the start service.
|
|
|
|
## No Legacy / No Backward Compatibility Constraint *(mandatory)*
|
|
|
|
TenantPilot is pre-production unless this spec explicitly records a compatibility exception.
|
|
|
|
- **Compatibility posture**: canonical v2 evidence path; no compatibility exception.
|
|
- **Legacy aliases, fallback readers, hidden routes, duplicate UI, old labels, or historical fixtures kept?**: no.
|
|
- **Why clean replacement is safe now**: Coverage v2 is inactive and not customer-facing. No production data migration or external contract compatibility is required. Spec 415 must not read v1 snapshots as v2 proof, dual-write v1/v2 evidence, or translate old gap taxonomy.
|
|
|
|
## UI Surface Impact *(mandatory - UI-COV-001)*
|
|
|
|
Does this spec add, remove, rename, or materially change any reachable UI surface?
|
|
|
|
- [x] No UI surface impact
|
|
- [ ] Existing page changed
|
|
- [ ] New page/route added
|
|
- [ ] Navigation changed
|
|
- [ ] Filament panel/provider surface changed
|
|
- [ ] New modal/drawer/wizard/action added
|
|
- [ ] New table/form/state added
|
|
- [ ] Customer-facing surface changed
|
|
- [ ] Dangerous action changed
|
|
- [ ] Status/evidence/review presentation changed
|
|
- [ ] Workspace/environment context presentation changed
|
|
|
|
## UI/Productization Coverage *(mandatory when UI Surface Impact is not "No UI surface impact"; otherwise write `N/A - no reachable UI surface impact` plus rationale)*
|
|
|
|
N/A - no reachable UI surface impact. This spec adds internal persistence, services, a queued job/start service, OperationRun tracking, authorization, and tests. It must not add Filament resources/pages, Blade views, routes, navigation, customer output, report output, or review/evidence UI activation.
|
|
|
|
Existing generic Monitoring -> Operations and central database-notification surfaces may show `OperationRun` records produced by this backend operation through the existing shared lifecycle contract. That is allowed only as existing technical/operational truth. This spec must not add feature-local notification copy, custom operation UI, custom run links, or new rendered capture controls without first amending `spec.md`, `plan.md`, and `tasks.md`.
|
|
|
|
## Product Surface Impact *(mandatory for UI-affecting specs; otherwise write `N/A - no rendered product surface changed` plus rationale)*
|
|
|
|
Reference: `docs/product/standards/product-surface-contract.md`.
|
|
|
|
- **Product Surface Contract applies?**: no - no rendered product surface changes.
|
|
- **Page archetype**: N/A.
|
|
- **Primary user question**: N/A.
|
|
- **Primary action**: N/A.
|
|
- **Surface budget result**: N/A.
|
|
- **Technical Annex / deep-link demotion**: N/A - no default product view exposes OperationRun, evidence IDs, source keys, payloads, fingerprints, or logs.
|
|
- **Canonical status vocabulary**: N/A - no product-facing labels added.
|
|
- **Visible complexity impact**: neutral; no rendered UI surface changes.
|
|
- **Product Surface exceptions**: none.
|
|
|
|
## Browser Verification Plan *(mandatory)*
|
|
|
|
- **Browser proof required?**: no.
|
|
- **No-browser rationale**: `N/A - no rendered UI surface changed`.
|
|
- **Focused path when required**: N/A.
|
|
- **Primary interaction to execute**: N/A.
|
|
- **Console, Livewire, Filament, network, and 500-error checks**: N/A.
|
|
- **Full-suite failure triage**: N/A; no browser lane is expected unless implementation changes rendered UI, routes, downloads, reports, or reachable actions.
|
|
|
|
## Human Product Sanity Check *(mandatory)*
|
|
|
|
- **Required?**: no.
|
|
- **No-human-sanity rationale**: N/A - no product surface changed.
|
|
- **Reviewer questions**: N/A for rendered UI; reviewers should instead verify that v2 evidence remains inactive and hidden from customer/operator proof surfaces.
|
|
- **Planned result location**: implementation-report.
|
|
|
|
## Product Surface Merge Gate Checklist *(mandatory)*
|
|
|
|
- [x] No-legacy posture or approved exception recorded.
|
|
- [x] Product Surface Impact is completed or `N/A` is justified.
|
|
- [x] Browser proof is completed or `N/A - no rendered UI surface changed` is justified.
|
|
- [x] Human Product Sanity is completed or not applicable with rationale.
|
|
- [x] Product Surface exceptions are documented or `none`.
|
|
- [x] Implementation report will state Livewire v4 compliance, provider registration location, global search posture, destructive/high-impact action posture, asset strategy, tests/browser result, deployment impact, visible complexity outcome, and no completed-spec rewrite assertion.
|
|
|
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
|
|
|
- **Cross-cutting feature?**: yes.
|
|
- **Interaction class(es)**: OperationRun execution lifecycle, terminal notification lifecycle, audit logging, provider Graph contract boundary.
|
|
- **Systems touched**: `OperationRun`, `OperationRunService`, `OperationRunType`, `OperationCatalog` if required by current repo conventions, `OperationSummaryKeys`, `GraphClientInterface`, `GraphContractRegistry`, `AuditLog`/audit recorder path, RBAC capability checks.
|
|
- **Existing pattern(s) to extend**: OperationRun lifecycle service, Graph contract registry/client seam, canonical capability registry, existing role capability map, existing audit recorder pattern.
|
|
- **Shared contract / presenter / builder / renderer to reuse**: OperationRun start/lifecycle contract where any start feedback/link is introduced. No rendered start UX is planned, so no local toast/link composition is allowed.
|
|
- **Why the existing shared path is sufficient or insufficient**: Existing OperationRun and Graph seams are sufficient for execution truth and provider calls. New local UI or notification semantics are unnecessary.
|
|
- **Allowed deviation and why**: none.
|
|
- **Consistency impact**: capture must not invent local operation notifications, local run-link wording, or local summary counter keys.
|
|
- **Review focus**: verify OperationRun transitions use `OperationRunService`, terminal notification remains lifecycle-owned, Graph calls go through `GraphClientInterface`, and summary counts use allowed keys.
|
|
|
|
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes for backend execution lifecycle; no rendered start surface.
|
|
- **Shared OperationRun UX contract/layer reused**: central OperationRun lifecycle and start contract. If any UI/start surface is unexpectedly added, implementation must stop and patch spec/plan/tasks before continuing.
|
|
- **Delegated start/completion UX behaviors**: no local UI behavior planned; terminal notification path remains central lifecycle mechanism through the existing generic OperationRun notification path only.
|
|
- **Local surface-owned behavior that remains**: initiation inputs only through an internal service/action; no Filament page/action, no toast, no local run link.
|
|
- **Queued DB-notification policy**: no queued DB notifications. Terminal notification behavior remains whatever `OperationRunService`/lifecycle emits for initiator-owned runs.
|
|
- **Terminal notification path**: central lifecycle mechanism / `OperationRunCompleted`.
|
|
- **Exception required?**: none.
|
|
|
|
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
|
|
|
|
- **Shared provider/platform boundary touched?**: yes.
|
|
- **Boundary classification**: mixed. Coverage resource/evidence ownership and outcome semantics are platform-core. Microsoft TCM/Graph source details are provider-owned source metadata.
|
|
- **Seams affected**: Coverage v2 resource type registry, Graph contract resolution, `GraphClientInterface`, provider connection provenance, source metadata, permission context redaction.
|
|
- **Neutral platform terms preserved or introduced**: provider, source contract, managed environment, evidence, resource, capture outcome, operation.
|
|
- **Provider-specific semantics retained and why**: `tcm`, `graph_v1_fallback`, and `graph_beta_experimental` remain from Spec 414 because this is a TCM-first Microsoft coverage path. They must not become generic platform ownership keys.
|
|
- **Why this does not deepen provider coupling accidentally**: source-specific values stay in registry/source metadata and resolver decisions. Concrete resource/evidence ownership remains `workspace_id`, `managed_environment_id`, and same-scope `provider_connection_id`; provider-native tenant IDs remain metadata.
|
|
- **Follow-up path**: Spec 416 Canonical Identity Engine is deferred; no multi-provider framework is introduced here.
|
|
|
|
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
|
|
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
|
|---|---|---|---|---|---|---|
|
|
| Coverage v2 internal capture persistence and service path | no | N/A | OperationRun and Graph service seams only | none | no | `N/A - backend/internal evidence capture only` |
|
|
|
|
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
N/A - no operator-facing surface change.
|
|
|
|
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
N/A - no operator-facing surface change. Raw and normalized payloads are persisted only in internal evidence storage and must not be exposed through customer/operator default views in this spec.
|
|
|
|
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
N/A - no operator-facing surface change.
|
|
|
|
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
N/A - no operator-facing surface change.
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: yes. Append-only Coverage v2 evidence becomes durable internal evidence truth for captured resource payloads.
|
|
- **New persisted entity/table/artifact?**: yes. `tenant_configuration_resources` and `tenant_configuration_resource_evidence` or repo-equivalent names.
|
|
- **New abstraction?**: yes. Bounded source contract resolver, capture service, resource upserter, evidence writer, payload normalizer, and outcome summarizer.
|
|
- **New enum/state/reason family?**: yes. Capture outcomes: `captured`, `capture_blocked_missing_contract`, `capture_blocked_permission`, `capture_blocked_beta`, `capture_blocked_unsupported`, `capture_failed`.
|
|
- **New cross-domain UI framework/taxonomy?**: no.
|
|
- **Current operator problem**: future operators must not receive false Coverage v2 claims or evidence-backed reports when no concrete payload evidence exists.
|
|
- **Existing structure is insufficient because**: Spec 414 registry/scope/claim guard has no concrete resource rows and no content payload persistence. v1 inventory/snapshot truth would create hidden dual truth and cannot enforce Coverage v2 source class, provider provenance, or claim safety.
|
|
- **Narrowest correct implementation**: concrete resources, append-only evidence, minimal generic normalization/hash, source-contract resolver, OperationRun-backed async capture, RBAC/scope guards, and tests for the initial 414 resource types only.
|
|
- **Ownership cost**: new migrations/models/services/jobs/tests and ongoing care for payload redaction, schema constraints, OperationRun keys, and provider contract mapping.
|
|
- **Alternative intentionally rejected**: using v1 snapshots as v2 evidence, storing metadata-only capture rows, or adding UI activation before evidence is durable. These alternatives would hide dual truth or overclaim coverage.
|
|
- **Release truth**: current-release foundation required by the completed 414 kernel and immediately following 416/417/418 lanes.
|
|
|
|
### Compatibility posture
|
|
|
|
This feature assumes a pre-production environment. Backward compatibility, legacy aliases, migration shims, historical fixtures, v1 fallback readers, v1-to-v2 adapters, and compatibility-specific tests are out of scope.
|
|
|
|
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
|
|
|
- **Test purpose / classification**: Unit for source contract resolution, normalization, hashing, redaction, and outcomes. Feature/PostgreSQL for persistence, JSONB, provider-connection same-scope constraints, OperationRun, RBAC, fake GraphClientInterface capture, and no-legacy guards.
|
|
- **Validation lane(s)**: fast-feedback, confidence, and PostgreSQL lane where JSONB/check constraints/composite FKs/partial indexes are introduced. Browser lane is N/A unless UI changes are introduced by amendment.
|
|
- **Why this classification and these lanes are sufficient**: The change is backend/runtime and persistence-heavy. Unit tests prove deterministic pure behavior; feature/PostgreSQL tests prove ownership, authorization, persistence, and OperationRun behavior. Browser tests would not add proof without a rendered UI surface.
|
|
- **New or expanded test families**: `tests/Unit/Support/TenantConfiguration` and `tests/Feature/TenantConfiguration` may expand with Spec 415-specific files.
|
|
- **Fixture / helper cost impact**: managed-environment, workspace, provider-connection, user-role, and fake Graph setup must remain opt-in and local to Spec 415 tests.
|
|
- **Heavy-family visibility / justification**: none planned. Do not add heavy-governance or browser families for this slice.
|
|
- **Special surface test profile**: N/A - no rendered UI surface changed.
|
|
- **Standard-native relief or required special coverage**: N/A.
|
|
- **Reviewer handoff**: verify no real Graph/TCM calls, no UI activation, no v1 adapter, no `tenant_id`, same-scope provider connection, allowed summary keys, redaction, and OperationRunService lifecycle.
|
|
- **Budget / baseline / trend impact**: none expected; if new tests materially slow fast-feedback, document in implementation report.
|
|
- **Escalation needed**: document-in-feature if focused tests require a new helper; follow-up-spec only if identity matching or surface activation becomes necessary.
|
|
- **Active feature PR close-out entry**: Guardrail / N/A no rendered UI surface changed.
|
|
- **Planned validation commands**:
|
|
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfiguration`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration`
|
|
- `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml tests/Feature/TenantConfiguration` when migrations add JSONB/check constraints/composite FKs/partial unique indexes
|
|
- `git diff --check`
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Persist Content-Backed Coverage v2 Evidence (Priority: P1)
|
|
|
|
As a platform engineer preparing Coverage v2 activation, I need concrete managed-environment resources and append-only evidence rows so future claims can be backed by durable payload truth.
|
|
|
|
**Independent Test**: Run the capture service against a fake GraphClientInterface response for an eligible resource type and assert concrete resource upsert plus append-only evidence persistence with raw payload, normalized payload, hash, and OperationRun link.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** an eligible registered resource type with an explicit source contract, **When** capture runs for a managed environment and same-scope provider connection, **Then** a concrete Coverage v2 resource exists with deterministic identity fields.
|
|
2. **Given** a successful payload fetch, **When** evidence is written, **Then** a new append-only evidence row stores raw payload, normalized payload, payload hash, source metadata, permission context, captured timestamp, and OperationRun link.
|
|
3. **Given** the same normalized payload captured twice, **When** hashes are compared, **Then** the payload hash is deterministic and identical.
|
|
4. **Given** a changed normalized payload captured later, **When** evidence is written, **Then** a new evidence row is appended instead of mutating prior evidence.
|
|
|
|
### User Story 2 - Fail Safe On Missing, Beta, Unsupported, Or Unauthorized Capture (Priority: P1)
|
|
|
|
As a release reviewer, I need capture eligibility to fail safe so v2 does not guess endpoints, certify beta data, or emit old v1 gap reasons.
|
|
|
|
**Independent Test**: Resolve capture eligibility for one TCM-aligned type, one Graph v1 fallback type, and the beta experimental type; assert missing contracts, beta default, unsupported states, and permission denial produce structured v2 outcomes only.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a registered type without an explicit source contract, **When** capture eligibility is resolved, **Then** the outcome is `capture_blocked_missing_contract`.
|
|
2. **Given** a beta experimental resource type without explicit beta capture opt-in, **When** capture is requested, **Then** the outcome is `capture_blocked_beta` and no customer/certified claim is possible.
|
|
3. **Given** an unsupported or out-of-scope type, **When** capture is requested, **Then** it is skipped safely without endpoint guessing.
|
|
4. **Given** a missing provider permission, **When** capture fails due to authorization from the provider, **Then** the outcome is `capture_blocked_permission` with sanitized context only.
|
|
5. **Given** any blocked/failed capture, **When** outcomes are inspected, **Then** no old v1 gap vocabulary is emitted.
|
|
|
|
### User Story 3 - Run Capture As An Observable Authorized Operation (Priority: P1)
|
|
|
|
As an operator-authorized backend workflow, I need generic capture to be authorized, queued when remote work is involved, and observable through OperationRun without rendering a new UI.
|
|
|
|
**Independent Test**: Start capture through the internal service for authorized and unauthorized users; assert 404/403 semantics, OperationRun creation/dedupe, queued job dispatch, OperationRunService transitions, numeric-only summary counts, and audit entry.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a non-member user, **When** capture start is attempted, **Then** access is denied as not found (404).
|
|
2. **Given** a workspace member without managed-environment entitlement, **When** capture start is attempted, **Then** access is denied as not found (404).
|
|
3. **Given** a managed-environment member without the capture capability, **When** capture start is attempted, **Then** access is denied as forbidden (403).
|
|
4. **Given** an authorized actor, **When** capture starts, **Then** a `tenant_configuration.capture` OperationRun is created or reused and remote work is queued.
|
|
5. **Given** the capture job runs, **When** it updates execution state, **Then** status/outcome transitions go through `OperationRunService`.
|
|
6. **Given** capture outcomes are summarized, **When** `summary_counts` is saved, **Then** only canonical numeric keys are used. Default keys are `total`, `processed`, `succeeded`, `skipped`, `failed`, and `errors_recorded` unless the implementation explicitly extends `OperationSummaryKeys::all()` with tests and spec-aligned rationale.
|
|
|
|
### User Story 4 - Keep Coverage v2 Inactive And Non-Legacy (Priority: P1)
|
|
|
|
As a product/release reviewer, I need proof that content-backed v2 evidence does not become an active customer/operator truth or compatibility bridge in this slice.
|
|
|
|
**Independent Test**: Static/feature guards assert no Filament resources/pages/routes/views/navigation are added, no v1-to-v2 adapter or dual-write path appears, no v1 snapshots are read as v2 evidence, and no Coverage v2 table introduces `tenant_id`.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** v2 evidence rows exist, **When** current customer/operator surfaces render, **Then** they do not display v2 coverage claims from this spec.
|
|
2. **Given** existing v1 runtime remains, **When** capture implementation is inspected, **Then** there is no v1-to-v2 adapter, fallback reader, or dual-write path.
|
|
3. **Given** new migrations/models, **When** schema and code are inspected, **Then** no Coverage v2 ownership field uses `tenant_id`.
|
|
4. **Given** raw provider payloads exist in evidence storage, **When** logs, OperationRun context/messages, notifications, and audit metadata are inspected, **Then** raw payloads, tokens, secrets, and PII are absent.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-415-001**: The system MUST keep Coverage v2 inactive for customer-facing and operator-facing proof surfaces in this spec.
|
|
- **FR-415-002**: The system MUST create or reuse concrete Coverage v2 resource persistence for managed-environment resources, using `workspace_id`, `managed_environment_id`, and `provider_connection_id` for provider-sourced records.
|
|
- **FR-415-003**: The system MUST create append-only Coverage v2 evidence persistence linked to concrete resource, workspace, managed environment, provider connection, OperationRun, source metadata, raw payload, normalized payload, payload hash, permission context, and capture timestamp.
|
|
- **FR-415-004**: The system MUST use JSONB for raw payload, normalized payload, and permission/source metadata where persisted.
|
|
- **FR-415-005**: The system MUST compute deterministic payload hashes from normalized payloads.
|
|
- **FR-415-006**: The system MUST normalize payloads minimally: stable JSON key ordering, configured volatile-field handling only where explicit, source metadata separation, and no semantic compare/render/restore mapping.
|
|
- **FR-415-007**: The system MUST resolve capture source contracts from the Coverage v2 registry and the repo's Graph contract path; it MUST NOT guess endpoints.
|
|
- **FR-415-008**: All Microsoft Graph calls MUST go through `GraphClientInterface`; direct HTTP/SDK/quick endpoint calls outside the contract path are forbidden.
|
|
- **FR-415-009**: The initial resource scope is limited to the Spec 414 resource types: `deviceAndAppManagementAssignmentFilter`, `deviceEnrollmentLimitRestriction`, `deviceEnrollmentPlatformRestriction`, `deviceEnrollmentStatusPageWindows10`, `appProtectionPolicyAndroid`, `appProtectionPolicyiOS`, `notificationMessageTemplate`, and `roleScopeTag`.
|
|
- **FR-415-010**: The implementation MUST classify each initial resource type as `captured`, `capture_blocked_missing_contract`, `capture_blocked_permission`, `capture_blocked_beta`, `capture_blocked_unsupported`, or `capture_failed`.
|
|
- **FR-415-011**: The implementation MUST prove every initial resource type has an explicit capture decision: each TCM-aligned type is either captured through an explicit contract or blocked with a clear missing-contract reason, the Graph v1 fallback type is captured or blocked with a clear contract reason, and the beta experimental type is blocked by default.
|
|
- **FR-415-012**: Beta experimental capture MUST be blocked by default unless this spec is amended with explicit beta capture opt-in and safety tests.
|
|
- **FR-415-013**: Missing contracts MUST produce `capture_blocked_missing_contract` without failure escalation or endpoint guessing.
|
|
- **FR-415-014**: Unsupported/out-of-scope types MUST be skipped safely.
|
|
- **FR-415-015**: Provider connection provenance MUST be same-scope: any stored `provider_connection_id` must belong to the same `workspace_id` and `managed_environment_id` as the resource/evidence row.
|
|
- **FR-415-016**: External Microsoft tenant/directory/subscription/account IDs MUST be metadata only and MUST NOT become platform ownership keys.
|
|
- **FR-415-017**: Capture start MUST enforce workspace membership, managed-environment entitlement, and capture capability server-side through Gate/Policy or existing capability resolver.
|
|
- **FR-415-018**: The default capture capability is `Capabilities::EVIDENCE_MANAGE` unless implementation discovers a more specific existing repo-approved capture capability. Adding a new capability is allowed only with registry, role-map, and tests in this spec.
|
|
- **FR-415-019**: Capture MUST create or reuse a canonical `tenant_configuration.capture` OperationRun for remote/provider-backed work.
|
|
- **FR-415-020**: Remote/provider capture MUST execute asynchronously through a queued job.
|
|
- **FR-415-021**: OperationRun status and outcome transitions MUST go through `OperationRunService`.
|
|
- **FR-415-022**: OperationRun `summary_counts` MUST use flat numeric values and canonical keys from `OperationSummaryKeys::all()`. Default planned keys are `total`, `processed`, `succeeded`, `skipped`, `failed`, and `errors_recorded`.
|
|
- **FR-415-023**: OperationRun context/messages, notifications, audit metadata, and logs MUST NOT include raw payloads, tokens, secrets, or PII.
|
|
- **FR-415-024**: Permission context MUST be redacted before persistence.
|
|
- **FR-415-025**: Capture MUST emit safe audit evidence for start/completion/failure attempts through the repo's existing `AuditRecorder` / `AuditEventBuilder` path, using stable action IDs `tenant_configuration.capture.started`, `tenant_configuration.capture.completed`, and `tenant_configuration.capture.failed`, including actor, workspace, managed environment, provider connection, OperationRun, resource type counts, and no raw payloads.
|
|
- **FR-415-026**: No v1-to-v2 adapter, dual write, fallback reader, old snapshot promotion, legacy route, or old gap taxonomy may be introduced.
|
|
- **FR-415-027**: No Filament Resource/Page, Blade view, route, navigation entry, customer report/review/evidence surface, or browser-visible Coverage v2 activation may be added in this spec.
|
|
- **FR-415-028**: An implementation report MUST include the capture eligibility matrix for all initial resource types.
|
|
|
|
### Non-Functional Requirements
|
|
|
|
- **NFR-415-001**: Capture must fail safe under missing contracts, missing permissions, beta resources, provider errors, and cross-scope provider connections.
|
|
- **NFR-415-002**: Tests must fake all Graph/TCM/provider calls. No test may call real Microsoft Graph or TCM.
|
|
- **NFR-415-003**: Raw provider payloads may live only in evidence storage and must not leak into logs, audit metadata, OperationRun context/messages, or notifications.
|
|
- **NFR-415-004**: New indexes must follow proven query paths only. JSONB GIN indexes are allowed only when the implementation adds a real query path.
|
|
- **NFR-415-005**: The implementation must remain bounded to the initial Spec 414 resource set.
|
|
- **NFR-415-006**: The queue and deployment impact must be documented: migrations and queue workers are expected; no asset or browser deployment change is expected.
|
|
|
|
### Required Redaction Keys
|
|
|
|
At minimum, redaction must handle case-insensitive keys containing:
|
|
|
|
- `access_token`
|
|
- `refresh_token`
|
|
- `id_token`
|
|
- `client_secret`
|
|
- `secret`
|
|
- `password`
|
|
- `private_key`
|
|
- `certificate`
|
|
- `authorization`
|
|
- `cookie`
|
|
- `set-cookie`
|
|
- `bearer`
|
|
|
|
## Key Entities *(include if feature involves data)*
|
|
|
|
- **Tenant Configuration Resource**: Concrete Coverage v2 resource observed in one workspace/managed environment/provider connection. It carries resource type, source class, canonical identity key, latest evidence state, and timestamps.
|
|
- **Tenant Configuration Resource Evidence**: Append-only payload evidence for a concrete Coverage v2 resource, linked to OperationRun and source metadata. It stores raw and normalized JSONB payloads, payload hash, redacted permission context, capture level/state, and captured timestamp.
|
|
- **Capture Outcome**: Non-UI service result classifying each resource type attempt as captured, blocked, skipped, or failed with a v2 reason.
|
|
- **OperationRun**: Execution truth for capture lifecycle, queue status, sanitized context, and numeric summary counts. It is not payload truth.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
- **SC-415-001**: Focused tests prove concrete v2 resources and append-only evidence can be persisted for an eligible fake source response.
|
|
- **SC-415-002**: Focused tests prove missing contract, beta default, unsupported, permission blocked, and failed capture outcomes are safe and use v2 vocabulary only.
|
|
- **SC-415-003**: Focused tests prove Graph calls use `GraphClientInterface` and no direct endpoint bypass exists in the capture path.
|
|
- **SC-415-004**: Focused tests prove same-scope `provider_connection_id` enforcement for resource/evidence writes.
|
|
- **SC-415-005**: Focused tests prove no `tenant_id` ownership field is introduced in new Coverage v2 tables/models/migrations.
|
|
- **SC-415-006**: Focused tests prove OperationRun creation/reuse, queued execution, service-owned transitions, numeric-only summary counts, and sanitized context.
|
|
- **SC-415-007**: Focused tests prove non-member 404, missing environment entitlement 404, missing capability 403, readonly denial, and authorized capture start.
|
|
- **SC-415-008**: Static/feature guards prove no v1 adapter, dual-write path, fallback reader, old snapshot promotion, old gap outcome vocabulary, or customer-facing v2 activation is introduced.
|
|
- **SC-415-009**: Implementation report includes the resource-type capture eligibility matrix and no-browser decision.
|
|
|
|
## Assumptions
|
|
|
|
- Spec 414 is implemented and accepted as the inactive Coverage v2 kernel. Repo artifacts show completed tasks, implementation report, tests, and kernel models/services/migration.
|
|
- `tenant_configuration_resources` and `tenant_configuration_resource_evidence` were deferred in Spec 414 and are expected to be added in Spec 415 unless implementation discovers equivalent repo-real tables.
|
|
- The local Boost database schema output may not reflect all migrations; implementation should use repo migrations/code as source of truth unless the Sail/PostgreSQL lane is explicitly run.
|
|
- Existing Graph contracts include some related Graph fallback/foundation types such as `notificationMessageTemplate`, `roleScopeTag`, and `assignmentFilter`, but exact source eligibility must be resolved by repo-real contract mapping rather than guessed endpoints.
|
|
- No rendered UI surface is required for capture start in this spec. Tests may start capture through an internal service/action.
|
|
|
|
## Risks
|
|
|
|
| Risk | Severity | Mitigation |
|
|
|---|---:|---|
|
|
| Capture becomes an activation/cutover spec | High | No UI, no customer proof, no v1 removal, no dual truth, stop-and-amend rule |
|
|
| Graph endpoints get guessed or hardcoded | High | Graph contract resolver + GraphClientInterface tests |
|
|
| Raw payloads/secrets leak | High | Redaction tests, OperationRun/audit/log context tests |
|
|
| Provider connection leaks across environments | High | Same-scope validation and tests |
|
|
| OperationRun lifecycle bypass | High | Use OperationRunService and existing guards |
|
|
| Summary counts drift into free-form keys | Medium | Use OperationSummaryKeys only; default existing keys |
|
|
| Capture tries to support too many types | Medium | Initial 414 resource types only; eligibility matrix |
|
|
| New tests become expensive | Medium | Unit/feature/pgsql only; fake Graph; no browser |
|
|
|
|
## Follow-up Spec Candidates
|
|
|
|
- Spec 416 - Canonical Identity Engine.
|
|
- Spec 417 - Coverage v2 Operator Surface.
|
|
- Spec 418 - Legacy Coverage Cutover and Removal.
|
|
- Spec 419 - Intune Core Comparable/Renderable Pack.
|
|
- Spec 420 - Certified Intune Core Coverage Pack.
|
|
- Spec 421 - Pilot Readiness Gate.
|
|
|
|
## Open Questions
|
|
|
|
None blocking. Implementation must document any repo-real source contract mismatch in the eligibility matrix rather than guessing endpoints or broadening scope.
|