284 lines
17 KiB
Markdown
284 lines
17 KiB
Markdown
# Implementation Plan: Spec 437 - Exchange Comparable Promotion Slice 1
|
|
|
|
**Branch**: `feat/437-exchange-comparable-promotion-slice-1` | **Date**: 2026-07-09 | **Spec**: [spec.md](./spec.md)
|
|
**Input**: Feature specification from `specs/437-exchange-comparable-promotion-slice-1/spec.md`
|
|
|
|
## Summary
|
|
|
|
Derive deterministic machine-comparable payloads for exactly `transportRule`, `remoteDomain`, and `inboundConnector` from immutable Spec 436 Exchange PowerShell content-backed evidence. The builder must consume only `normalized_payload` as material input, require a valid SHA-256 `payload_hash` plus content-backed/captured provenance gates, preserve existing evidence rows, keep persisted coverage state unchanged, represent protected values through redacted presence/count/safe-state semantics, emit stable identity as a scoped app-keyed HMAC anchor, enforce value policies for exact safe fields, keep compare-shape/source contract metadata hash-relevant, and add no renderable output, certification, restore, UI, customer output, jobs, schedules, listeners, migrations, `tenant_id`, new OperationRun type, or Exchange-specific compare table.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4 / Laravel 12
|
|
**Primary Dependencies**: Laravel, Pest 4, existing TenantConfiguration Coverage v2 services
|
|
**Storage**: Existing PostgreSQL-backed Coverage v2 tables are read only for this slice; no migration, comparable artifact persistence, or persisted coverage-level promotion planned
|
|
**Testing**: Pest unit and feature tests
|
|
**Validation Lanes**: fast-feedback and confidence; browser N/A
|
|
**Target Platform**: Laravel Sail locally, Dokploy/container deployment for staging/production
|
|
**Project Type**: Laravel monolith under `apps/platform`
|
|
**Performance Goals**: deterministic in-memory comparable derivation with no remote/provider calls
|
|
**Constraints**: normalized-payload-only material input, valid SHA-256 payload hash and content-backed/captured provenance required, evidence immutability, no persisted `coverage_level = comparable`, protected config redaction, exact safe field value policies, scoped HMAC identity anchors, no rendered surface
|
|
**Scale/Scope**: exactly three Exchange PowerShell resource types
|
|
|
|
## 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.
|
|
- **Native vs custom classification summary**: N/A.
|
|
- **Shared-family relevance**: backend Coverage v2 evidence/compare semantics only.
|
|
- **State layers in scope**: none.
|
|
- **Audience modes in scope**: N/A.
|
|
- **Decision/diagnostic/raw hierarchy plan**: N/A at UI layer; raw/provider/protected values must not enter comparable output.
|
|
- **Raw/support gating plan**: raw evidence remains internal storage only; comparable output contains no raw/protected exact values and does not update persisted coverage/readiness state.
|
|
- **One-primary-action / duplicate-truth control**: N/A.
|
|
- **Handling modes by drift class or surface**: hard stop if any rendered surface, route, action, report, download, or customer output appears.
|
|
- **Repository-signal treatment**: review-mandatory for any accidental UI/read-model/customer/report/trigger file change.
|
|
- **Special surface test profiles**: N/A.
|
|
- **Required tests or manual smoke**: `N/A - no rendered UI surface changed`.
|
|
- **Exception path and spread control**: none.
|
|
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
|
|
- **UI/Productization coverage decision**: No UI surface impact.
|
|
- **Coverage artifacts to update**: none.
|
|
- **No-impact rationale**: comparable-only backend service and tests.
|
|
- **Navigation / Filament provider-panel handling**: no changes.
|
|
- **Screenshot or page-report need**: no.
|
|
|
|
## Product Surface Contract Plan
|
|
|
|
- **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md` checked for no-rendered-surface path.
|
|
- **No-legacy posture**: canonical bounded addition; no aliases, fallback readers, hidden routes, duplicate UI, old labels, or legacy fixtures.
|
|
- **Page archetype and surface budget plan**: N/A.
|
|
- **Technical Annex and deep-link demotion plan**: N/A at runtime; OperationRun/evidence/raw IDs/source keys/payloads are not rendered.
|
|
- **Canonical status vocabulary plan**: N/A - no product status vocabulary.
|
|
- **Product Surface exceptions**: none.
|
|
- **Browser verification plan**: `N/A - no rendered UI surface changed`.
|
|
- **Human Product Sanity plan**: N/A.
|
|
- **Visible complexity outcome target**: neutral.
|
|
- **Implementation report target**: `specs/437-exchange-comparable-promotion-slice-1/implementation-report.md`.
|
|
|
|
## Filament / Livewire / Deployment Posture
|
|
|
|
- **Livewire v4 compliance**: unchanged; no Livewire/Filament code changes.
|
|
- **Panel provider registration location**: unchanged; no panel provider registration change. Laravel panel providers remain under `apps/platform/bootstrap/providers.php`.
|
|
- **Global search posture**: unchanged; no Filament Resource changed.
|
|
- **Destructive/high-impact action posture**: none.
|
|
- **Asset strategy**: no assets; no new `filament:assets` requirement.
|
|
- **Testing plan**: focused unit and feature tests only; browser N/A.
|
|
- **Deployment impact**: no env vars, migrations, queues, scheduler, storage, assets, routes, jobs, listeners, or commands.
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes, backend Coverage v2 comparable semantics.
|
|
- **Systems touched**: existing TenantConfiguration evidence/comparable service layer.
|
|
- **Shared abstractions reused**: Spec 436 normalized evidence payloads; existing evidence models; existing hash/provenance metadata; app-keyed HMAC identity anchoring.
|
|
- **New abstraction introduced? why?**: bounded `ExchangePowerShellComparablePayloadBuilder` because existing generic/ExchangeTeams compare paths do not enforce Spec 436 normalized-payload-only material input, required content-backed provenance, target-specific protected-value safety, exact safe field value policies, scoped identity HMAC anchoring, and no persisted coverage-level promotion for this slice.
|
|
- **Why the existing abstraction was sufficient or insufficient**: Evidence storage is sufficient. Existing generic/ExchangeTeams comparable normalizers are insufficient and forbidden for this input path.
|
|
- **Bounded deviation / spread control**: provider-specific builder stays local to Exchange PowerShell evidence for three types; no platform-core status/persistence/UI/customer seam change.
|
|
|
|
## OperationRun UX Impact
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: no.
|
|
- **Central contract reused**: N/A.
|
|
- **Delegated UX behaviors**: N/A.
|
|
- **Surface-owned behavior kept local**: none.
|
|
- **Queued DB-notification policy**: N/A.
|
|
- **Terminal notification path**: N/A.
|
|
- **Exception path**: none.
|
|
|
|
OperationRun implementation posture:
|
|
|
|
- Do not add or modify `OperationRunType` or `OperationCatalog`.
|
|
- Do not use Exchange PowerShell invocation runs as comparable owners.
|
|
- Do not use OperationRun context as input.
|
|
- Do not store comparable payloads, deltas, raw output, transcripts, protected config, or customer text in OperationRun context/messages/notifications.
|
|
|
|
## Provider Boundary & Portability Fit
|
|
|
|
- **Shared provider/platform boundary touched?**: yes.
|
|
- **Provider-owned seams**: Exchange PowerShell comparable payload builder and target-specific safe field mapping.
|
|
- **Platform-core seams**: Coverage v2 evidence remains source truth; ownership remains workspace + managed environment + provider connection.
|
|
- **Neutral platform terms / contracts preserved**: evidence, comparable payload, normalized payload, resource type, workload, provider connection, managed environment, operation run provenance.
|
|
- **Retained provider-specific semantics and why**: `transportRule`, `remoteDomain`, `inboundConnector`, Exchange PowerShell source metadata, and protected Exchange config semantics are required for this bounded slice.
|
|
- **Bounded extraction or follow-up path**: Spec 438 internal render model is separate.
|
|
|
|
## Constitution Check
|
|
|
|
| Principle / Gate | Result | Notes |
|
|
|---|---|---|
|
|
| Inventory-first / evidence truth | PASS | Comparable derives only when immutable evidence is content-backed/captured and does not promote persisted evidence coverage level. |
|
|
| Read/write separation | PASS | No provider writes, restore, apply, destructive action, or UI action. |
|
|
| Graph contract path | PASS | No Graph or Exchange call in Spec 437. |
|
|
| Deterministic capabilities | PASS | Comparable derivation is deterministic and testable. |
|
|
| Workspace isolation | PASS | No new ownership truth; evidence scope remains existing workspace/managed-environment/provider connection. |
|
|
| RBAC-UX | PASS | No routes/actions/resources/global search. |
|
|
| OperationRun truth | PASS | No new OperationRun type; context not input. |
|
|
| Evidence anchor contract | PASS | No fallback-to-latest or OperationRun-as-proof. |
|
|
| Data minimization | PASS | Raw/protected values excluded from comparable payloads; unexpected exact protected/sensitive values block output. |
|
|
| Product Surface | PASS | N/A - no rendered UI surface changed. |
|
|
| Customer output | PASS | No customer output, reports, Review Packs, PDFs, or customer claims. |
|
|
| Provider boundary | PASS | Provider-specific builder is bounded and local. |
|
|
| Test governance | PASS | Unit/Feature only; Browser N/A. |
|
|
| Proportionality | PASS | One bounded helper; no persistence/status/UI framework. |
|
|
| TCM/Coverage v2 cutover guard | PASS | No legacy adapters, fallback readers, dual writes, tenant_id, or customer claims. |
|
|
|
|
## Test Governance Check
|
|
|
|
- **Test purpose / classification by changed surface**: Unit for builder/comparator determinism and redaction; Feature for evidence immutability and no-promotion/no-surface guards.
|
|
- **Affected validation lanes**: fast-feedback, confidence.
|
|
- **Why this lane mix is the narrowest sufficient proof**: Spec 437 changes backend comparable behavior only; no browser/render/provider execution lane is needed.
|
|
- **Narrowest proving command(s)**:
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec437 --compact`
|
|
- targeted regressions listed in Phase 6.
|
|
- **Fixture / helper / factory / seed / context cost risks**: reuse existing TenantConfiguration evidence factories/helpers; avoid global defaults.
|
|
- **Expensive defaults or shared helper growth introduced?**: no.
|
|
- **Heavy-family additions, promotions, or visibility changes**: none.
|
|
- **Surface-class relief / special coverage rule**: N/A.
|
|
- **Closing validation and reviewer handoff**: reviewer must verify valid payload hash and content-backed/captured provenance gates, scoped HMAC identity anchors, exact safe field value policies, no raw payload/context input, no evidence mutation, no UI/customer/trigger/persistence expansion, and exact target scope.
|
|
- **Budget / baseline / trend follow-up**: none.
|
|
- **Review-stop questions**: lane fit, redaction, evidence immutability, no-product-surface, no-mini-platform.
|
|
- **Escalation path**: none unless implementation requires renderable, persistence, UI, or migration; then amend/split.
|
|
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
|
|
- **Why no dedicated follow-up spec is needed**: comparable-only builder is the dedicated bounded slice; renderable is already deferred to Spec 438.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation
|
|
|
|
```text
|
|
specs/437-exchange-comparable-promotion-slice-1/
|
|
|-- checklists/
|
|
| `-- requirements.md
|
|
|-- implementation-report.md
|
|
|-- plan.md
|
|
|-- spec.md
|
|
`-- tasks.md
|
|
```
|
|
|
|
### Source Code
|
|
|
|
Likely runtime paths if implementation proceeds:
|
|
|
|
```text
|
|
apps/platform/app/Services/TenantConfiguration/
|
|
|-- ExchangePowerShellComparablePayloadBuilder.php
|
|
`-- ExchangePowerShellCoverageComparator.php # only if needed
|
|
|
|
apps/platform/tests/Unit/Support/TenantConfiguration/
|
|
`-- Spec437ExchangeComparablePayloadBuilderTest.php
|
|
|
|
apps/platform/tests/Feature/TenantConfiguration/
|
|
`-- Spec437ExchangeComparablePromotionFeatureTest.php
|
|
```
|
|
|
|
**Structure Decision**: Use existing TenantConfiguration service/test locations. Do not create new base folders, migrations, routes, UI surfaces, jobs, listeners, schedules, commands, or customer-output paths.
|
|
|
|
## Complexity Tracking
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
|---|---|---|
|
|
| New bounded builder helper | Required to enforce normalized-payload-only input and protected Exchange target semantics. | Reusing generic/ExchangeTeams normalizer would violate Spec 437 input and redaction gates. |
|
|
|
|
## Proportionality Review
|
|
|
|
- **Current operator problem**: Future compare/render/certification work cannot safely proceed until Exchange evidence can be compared without leaking protected configuration or overclaiming readiness.
|
|
- **Existing structure is insufficient because**: Existing generic/ExchangeTeams comparable path predates Spec 436 normalized evidence and includes broader renderable behavior that Spec 437 explicitly defers.
|
|
- **Narrowest correct implementation**: One local builder for three concrete Exchange PowerShell target types; comparator only if needed; no persisted comparable artifact or coverage-level promotion.
|
|
- **Ownership cost created**: Focused tests and future review burden around redaction/determinism.
|
|
- **Alternative intentionally rejected**: Raw payload compare, normalized provider payload compare outside Spec 436 evidence, and ExchangeTeamsComparablePayloadNormalizer reuse.
|
|
- **Release truth**: Current-release prerequisite for the Exchange roadmap.
|
|
|
|
## Phase 0 - Preflight
|
|
|
|
- Capture branch and HEAD.
|
|
- Capture `git status --short`.
|
|
- Confirm Spec 436 PASS/merge-ready or merged at current base.
|
|
- Confirm target types content-backed.
|
|
- Confirm comparable-only scope.
|
|
- Confirm renderable deferred.
|
|
- Confirm no UI/jobs/schedules/listeners/migration scope.
|
|
- Confirm no hard-gate stop condition.
|
|
|
|
Deliverable: Preflight documented in `implementation-report.md`.
|
|
|
|
## Phase 1 - Comparable Builder
|
|
|
|
- Add Exchange PowerShell comparable payload builder.
|
|
- Use `normalized_payload` only.
|
|
- Require a valid SHA-256 `payload_hash`, `evidence_state = content_backed`, `coverage_level = content_backed`, and `capture_outcome = captured`.
|
|
- Forbid raw payload/stdout/stderr/transcript input.
|
|
- Forbid OperationRun context input.
|
|
- Add deterministic output shape.
|
|
|
|
Deliverable: Comparable builder exists and is covered by unit tests.
|
|
|
|
## Phase 2 - Target Comparable Payloads
|
|
|
|
- Add `transportRule` comparable payload.
|
|
- Add `remoteDomain` comparable payload.
|
|
- Add `inboundConnector` comparable payload.
|
|
- Encode protected config using redacted presence/count/safe-state semantics.
|
|
- Block unexpected exact protected/sensitive values rather than sanitizing them through.
|
|
- Validate exact safe fields by target-specific value policy before output.
|
|
- Emit stable identity through scoped HMAC anchors instead of exact values or unsalted hashes.
|
|
- Keep compare-shape and normalizer contract metadata hash-relevant; exclude run/evidence provenance from comparable hash.
|
|
- Exclude volatile fields.
|
|
|
|
Deliverable: Three target comparable payloads.
|
|
|
|
## Phase 3 - Determinism / Delta Semantics
|
|
|
|
- Prove deterministic comparable payload.
|
|
- Prove material changes produce changed comparable payload or machine deltas.
|
|
- Prove volatile changes ignored.
|
|
- Prove provider ordering deterministic.
|
|
- Add comparator only if repo architecture requires it.
|
|
|
|
Deliverable: Comparable semantics are deterministic.
|
|
|
|
## Phase 4 - Safety / Immutability
|
|
|
|
- Prove evidence rows are not mutated.
|
|
- Prove persisted coverage/resource/resource-type state is not promoted to comparable.
|
|
- Prove no raw payload leaks.
|
|
- Prove OperationRun context is not compare input.
|
|
- Prove no renderable/customer/cert/restore state.
|
|
|
|
Deliverable: Comparable promotion without overclaim.
|
|
|
|
## Phase 5 - Product Surface Guard
|
|
|
|
- Prove no UI/routes/jobs/schedules/listeners.
|
|
- Prove no report/review-pack/PDF/customer output.
|
|
- Prove browser N/A.
|
|
|
|
Deliverable: No product surface changed.
|
|
|
|
## Phase 6 - Regression / Report
|
|
|
|
- Run focused tests.
|
|
- Run regressions.
|
|
- Run Pint.
|
|
- Run `git diff --check`.
|
|
- Complete implementation report.
|
|
|
|
Deliverable: Spec 437 implementation report.
|
|
|
|
## Rollout Considerations
|
|
|
|
- No migration or deployment flag.
|
|
- No queue/scheduler/storage/asset change.
|
|
- No `filament:assets` requirement introduced by this spec.
|
|
- Comparable derivation remains internal backend behavior until a later spec explicitly adds render/read-model/customer surfaces.
|
|
|
|
## Risk Controls
|
|
|
|
- Hard stop on raw payload/context input.
|
|
- Hard stop on protected exact value leakage.
|
|
- Hard stop on missing content-backed/captured provenance.
|
|
- Hard stop on invalid payload hash or malformed exact safe field values.
|
|
- Hard stop on evidence mutation.
|
|
- Hard stop on UI/read-model/customer/report/trigger/migration expansion.
|
|
- Hard stop on new OperationRun type or tenant_id ownership truth.
|
|
- Use static/no-surface tests in addition to behavior tests.
|