merge: agent session work
This commit is contained in:
commit
8079bd9cdd
@ -7,23 +7,23 @@ ## Existing Entities (Confirmed)
|
|||||||
### BaselineProfile
|
### BaselineProfile
|
||||||
Represents a baseline definition.
|
Represents a baseline definition.
|
||||||
|
|
||||||
- Fields (expected): `id`, `name`, `description`, `scope` (jsonb), `created_by`, timestamps
|
- Fields (confirmed in migrations): `id`, `workspace_id`, `name`, `description`, `version_label`, `status`, `scope_jsonb` (jsonb), `active_snapshot_id`, `created_by_user_id`, timestamps
|
||||||
- Relationships: has many snapshots; assigned to tenants via `BaselineTenantAssignment`
|
- Relationships: has many snapshots; assigned to tenants via `BaselineTenantAssignment`
|
||||||
|
|
||||||
### BaselineSnapshot
|
### BaselineSnapshot
|
||||||
Immutable capture of baseline state at a point in time.
|
Immutable capture of baseline state at a point in time.
|
||||||
|
|
||||||
- Fields (expected): `id`, `baseline_profile_id`, `captured_at`, `status`, `operation_run_id`, timestamps
|
- Fields (confirmed in migrations): `id`, `workspace_id`, `baseline_profile_id`, `snapshot_identity_hash`, `captured_at`, `summary_jsonb` (jsonb), timestamps
|
||||||
- Relationships: has many items; belongs to baseline profile
|
- Relationships: has many items; belongs to baseline profile
|
||||||
|
|
||||||
### BaselineSnapshotItem
|
### BaselineSnapshotItem
|
||||||
One item in a baseline snapshot.
|
One item in a baseline snapshot.
|
||||||
|
|
||||||
- Fields (expected):
|
- Fields (confirmed in migrations):
|
||||||
- `id`, `baseline_snapshot_id`
|
- `id`, `baseline_snapshot_id`
|
||||||
|
- `subject_type`
|
||||||
|
- `subject_external_id`
|
||||||
- `policy_type`
|
- `policy_type`
|
||||||
- `external_id`
|
|
||||||
- `subject_json` (jsonb) or subject fields
|
|
||||||
- `baseline_hash` (string)
|
- `baseline_hash` (string)
|
||||||
- `meta_jsonb` (jsonb)
|
- `meta_jsonb` (jsonb)
|
||||||
- timestamps
|
- timestamps
|
||||||
@ -110,6 +110,7 @@ ### 4) Inventory meta contract
|
|||||||
|
|
||||||
- Implemented as a dedicated builder class (no schema change required).
|
- Implemented as a dedicated builder class (no schema change required).
|
||||||
- Used by baseline capture to compute `baseline_hash` and by compare to compute `current_hash`.
|
- Used by baseline capture to compute `baseline_hash` and by compare to compute `current_hash`.
|
||||||
|
- Persist the exact contract payload used for hashing to `baseline_snapshot_items.meta_jsonb.meta_contract` (versioned) for auditability/reproducibility.
|
||||||
|
|
||||||
## Potential Migrations (Likely)
|
## Potential Migrations (Likely)
|
||||||
|
|
||||||
|
|||||||
@ -147,15 +147,21 @@ ### Step 1 — Baseline scope schema + UI picker
|
|||||||
|
|
||||||
### Step 2 — Inventory Meta Contract (explicit hash input)
|
### Step 2 — Inventory Meta Contract (explicit hash input)
|
||||||
|
|
||||||
Goal: implement FR-116v1-04, FR-116v1-05, FR-116v1-06.
|
Goal: implement FR-116v1-04, FR-116v1-05, FR-116v1-06, FR-116v1-06a.
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
- Introduce a dedicated contract builder (e.g. `App\Services\Baselines\InventoryMetaContract`) that returns a normalized array for hashing.
|
- Introduce a dedicated contract builder (e.g. `App\Services\Baselines\InventoryMetaContract`) that returns a normalized array for hashing.
|
||||||
|
- Contract output must be explicitly versioned (e.g., `meta_contract.version = 1`) so future additions do not retroactively change v1 semantics.
|
||||||
|
- Contract signals are best-effort: missing signals are represented as `null` (not omitted) to keep hashing stable across partial inventories.
|
||||||
- Update baseline capture hashing (`BaselineSnapshotIdentity::hashItemContent()` or the capture service) to hash the contract output only.
|
- Update baseline capture hashing (`BaselineSnapshotIdentity::hashItemContent()` or the capture service) to hash the contract output only.
|
||||||
|
- Persist the exact contract payload used for hashing to `baseline_snapshot_items.meta_jsonb.meta_contract` for auditability/reproducibility.
|
||||||
|
- Persist observation metadata alongside the hash in `baseline_snapshot_items.meta_jsonb` (at minimum: `fidelity`, `source`, `observed_at`; when available: `observed_operation_run_id`).
|
||||||
- Update baseline compare to compute `current_hash` using the same contract builder.
|
- Update baseline compare to compute `current_hash` using the same contract builder.
|
||||||
|
- Current-state `observed_at` is derived from persisted inventory evidence (`inventory_items.last_seen_at`) and MUST NOT require per-item external hydration calls during compare.
|
||||||
|
- Define “latest successful snapshot” (v1) as `baseline_profiles.active_snapshot_id` and ensure compare start is blocked when it is `null` (no “pick newest captured_at” fallback).
|
||||||
|
|
||||||
Tests:
|
Tests:
|
||||||
- Add a small Pest test for contract normalization stability (ordering, missing fields, nullability).
|
- Add a small Pest test for contract normalization stability (ordering, missing fields, nullability) in `tests/Unit/Baselines/InventoryMetaContractTest.php`.
|
||||||
- Update baseline capture/compare tests if they currently assume hashing full `meta_jsonb`.
|
- Update baseline capture/compare tests if they currently assume hashing full `meta_jsonb`.
|
||||||
|
|
||||||
### Step 3 — Inventory sync coverage recording
|
### Step 3 — Inventory sync coverage recording
|
||||||
@ -233,6 +239,7 @@ ### Step 7 — Ops UX + auditability
|
|||||||
- coverage summary and uncovered lists when partial
|
- coverage summary and uncovered lists when partial
|
||||||
- numeric summary counts using canonical keys only
|
- numeric summary counts using canonical keys only
|
||||||
- per-change-type finding counts in `operation_runs.context.findings.counts_by_change_type`
|
- per-change-type finding counts in `operation_runs.context.findings.counts_by_change_type`
|
||||||
|
- Treat the `operation_runs` record as the canonical audit trail for this feature slice (do not add parallel “audit summary” persistence for the same data).
|
||||||
|
|
||||||
Tests:
|
Tests:
|
||||||
- Add a regression test that asserts `summary_counts` contains only allowed keys and numeric values (where a helper exists).
|
- Add a regression test that asserts `summary_counts` contains only allowed keys and numeric values (where a helper exists).
|
||||||
|
|||||||
@ -14,6 +14,7 @@ ## Spec Scope Fields *(mandatory)*
|
|||||||
- **Data Ownership**:
|
- **Data Ownership**:
|
||||||
- Workspace-owned: Baseline profiles and baseline snapshots
|
- Workspace-owned: Baseline profiles and baseline snapshots
|
||||||
- Tenant-scoped (within a workspace): Operation runs for baseline capture/compare; drift findings produced by compare
|
- Tenant-scoped (within a workspace): Operation runs for baseline capture/compare; drift findings produced by compare
|
||||||
|
- Baseline snapshots are workspace-owned standards captured from a chosen tenant, but snapshot items MUST NOT persist tenant identifiers (e.g., no `tenant_id` column on snapshot items).
|
||||||
- **RBAC**:
|
- **RBAC**:
|
||||||
- Workspace (Baselines):
|
- Workspace (Baselines):
|
||||||
- `workspace_baselines.view`: view baseline profiles + snapshots
|
- `workspace_baselines.view`: view baseline profiles + snapshots
|
||||||
@ -31,7 +32,7 @@ ### Session 2026-03-01
|
|||||||
|
|
||||||
- Q: Should finding identity be stable across baseline re-captures, or tied to a specific baseline snapshot? → A: Tie finding identity to `baseline_snapshot_id` (stable within a snapshot; re-capture creates new finding identities).
|
- Q: Should finding identity be stable across baseline re-captures, or tied to a specific baseline snapshot? → A: Tie finding identity to `baseline_snapshot_id` (stable within a snapshot; re-capture creates new finding identities).
|
||||||
- Q: In v2, should drift dimensions be stored as flags on a single finding, or as separate findings per dimension? → A: Use one finding with dimension flags (no separate findings per dimension).
|
- Q: In v2, should drift dimensions be stored as flags on a single finding, or as separate findings per dimension? → A: Use one finding with dimension flags (no separate findings per dimension).
|
||||||
- Q: When running a compare, which baseline snapshot should be used by default? → A: Default to latest successful baseline snapshot for the baseline profile; allow explicitly selecting a snapshot.
|
- Q: When running a compare, which baseline snapshot should be used by default? → A: Default to the baseline profile’s `active_snapshot_id` (updated only by successful captures); allow explicitly selecting a snapshot.
|
||||||
- Q: When coverage is missing for a policy type, should compare emit any findings for that type? → A: Skip all finding emission for uncovered types (no `missing_policy`, no `unexpected_policy`, no `different_version`).
|
- Q: When coverage is missing for a policy type, should compare emit any findings for that type? → A: Skip all finding emission for uncovered types (no `missing_policy`, no `unexpected_policy`, no `different_version`).
|
||||||
|
|
||||||
## Outcomes
|
## Outcomes
|
||||||
@ -43,13 +44,14 @@ ## Outcomes
|
|||||||
|
|
||||||
## Definitions
|
## Definitions
|
||||||
|
|
||||||
- **Policy subject**: A compare object uniquely identified by `(tenant_id, policy_type, external_id)`.
|
- **Subject key**: A compare object identity independent of tenant, identified by `(policy_type, external_id)`.
|
||||||
- **Policy state**: A normalized representation of a policy subject, containing a deterministic hash, fidelity, and observation metadata.
|
- **Tenant subject**: A subject key within a tenant context, identified by `(tenant_id, policy_type, external_id)`.
|
||||||
|
- **Policy state**: A normalized representation of a tenant subject, containing a deterministic hash, fidelity, and observation metadata.
|
||||||
- **Fidelity**:
|
- **Fidelity**:
|
||||||
- **meta**: drift signal based on a stable “inventory meta contract” (signal-based fields)
|
- **meta**: drift signal based on a stable “inventory meta contract” (signal-based fields)
|
||||||
- **content**: drift signal based on canonicalized policy content (semantic)
|
- **content**: drift signal based on canonicalized policy content (semantic)
|
||||||
- **Effective scope**: The expanded set of policy types processed by a run.
|
- **Effective scope**: The expanded set of policy types processed by a run.
|
||||||
- **Coverage**: Which policy types are confirmed to be present/updated in the current state at the time of compare.
|
- **Coverage**: Which policy types are confirmed to be present/updated in the tenant current state at the time of compare.
|
||||||
|
|
||||||
## Assumptions
|
## Assumptions
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ ## Requirements *(mandatory)*
|
|||||||
|
|
||||||
- **Run observability**: Every capture/compare run must have a visible run identity, scope context, coverage context, and outcome.
|
- **Run observability**: Every capture/compare run must have a visible run identity, scope context, coverage context, and outcome.
|
||||||
- **Safety**: Compare must never claim missing policies for policy types where current-state coverage is not proven.
|
- **Safety**: Compare must never claim missing policies for policy types where current-state coverage is not proven.
|
||||||
- **Tenant isolation**: All stored states and findings are tenant-scoped; cross-tenant access must be deny-as-not-found.
|
- **Tenant isolation**: Inventory items, operation runs, and findings are tenant-scoped; cross-tenant access must be deny-as-not-found. Baseline profiles/snapshots are workspace-owned and must not persist tenant identifiers.
|
||||||
|
|
||||||
### Operational UX Contract (Ops-UX)
|
### Operational UX Contract (Ops-UX)
|
||||||
|
|
||||||
@ -158,11 +160,18 @@ #### v1 — Meta-fidelity baseline compare (sellable)
|
|||||||
- **FR-116v1-04 Inventory meta contract**: The system MUST define and persist a stable “inventory meta contract” (signal-based fields) for drift hashing.
|
- **FR-116v1-04 Inventory meta contract**: The system MUST define and persist a stable “inventory meta contract” (signal-based fields) for drift hashing.
|
||||||
- Minimum required signals: type identifier, version marker (when available), last modified time (when available), scope tags (when available), and assignment target count (when available).
|
- Minimum required signals: type identifier, version marker (when available), last modified time (when available), scope tags (when available), and assignment target count (when available).
|
||||||
- Drift hashing for v1 MUST be based only on this contract (not arbitrary meta fields).
|
- Drift hashing for v1 MUST be based only on this contract (not arbitrary meta fields).
|
||||||
|
- Contract outputs MUST be versioned so future additions do not retroactively change v1 semantics (e.g., `meta_contract.version = 1`).
|
||||||
|
- For baseline snapshot items, the exact contract payload used for hashing MUST be persisted in the snapshot item `meta_jsonb` (e.g., `meta_jsonb.meta_contract`).
|
||||||
- **FR-116v1-05 Provide current-state policy states (meta fidelity)**: For all policy subjects in effective scope, the system MUST produce a normalized policy state for compare, including:
|
- **FR-116v1-05 Provide current-state policy states (meta fidelity)**: For all policy subjects in effective scope, the system MUST produce a normalized policy state for compare, including:
|
||||||
- subject key (policy type + external id), deterministic hash, fidelity=`meta`, source indicator, and observed timestamp.
|
- subject key (policy type + external id), deterministic hash, fidelity=`meta`, source indicator, and observed timestamp.
|
||||||
- **FR-116v1-06 Baseline capture stores states (not raw)**: Baseline capture MUST store per-subject snapshot items that include the subject identity and the captured hash + fidelity + source.
|
- In v1, `observed_at` MUST be derived from persisted inventory evidence (`inventory_items.last_seen_at`), not from per-item external hydration calls during compare.
|
||||||
|
- In v1, `source` MUST indicate the meta-fidelity source (e.g., `inventory_meta_contract:v1`) and MAY include stable provenance (e.g., `inventory_items.last_seen_operation_run_id`) for traceability.
|
||||||
|
- **FR-116v1-06 Baseline capture stores states (not raw)**: Baseline capture MUST store per-subject snapshot items that include the subject identity and the captured hash + fidelity + source + observed timestamp.
|
||||||
- Baseline snapshots MUST NOT contain out-of-scope items.
|
- Baseline snapshots MUST NOT contain out-of-scope items.
|
||||||
|
- Snapshot items MUST store observation metadata in `baseline_snapshot_items.meta_jsonb` (at minimum: `fidelity`, `source`, `observed_at`; when available: `observed_operation_run_id`).
|
||||||
- **FR-116v1-06a Compare snapshot selection**: Baseline compare MUST, by default, use the latest successful baseline snapshot of the selected baseline profile.
|
- **FR-116v1-06a Compare snapshot selection**: Baseline compare MUST, by default, use the latest successful baseline snapshot of the selected baseline profile.
|
||||||
|
- Definition (v1): “latest successful baseline snapshot” is `baseline_profiles.active_snapshot_id` (updated only after a successful capture run persists a snapshot + items).
|
||||||
|
- If `active_snapshot_id` is `null`, compare start MUST be blocked with a clear precondition failure (no implicit “pick the newest captured_at” fallback).
|
||||||
- The UI MAY allow selecting a specific snapshot explicitly for historical comparisons.
|
- The UI MAY allow selecting a specific snapshot explicitly for historical comparisons.
|
||||||
- **FR-116v1-07 Coverage guard**: Compare MUST check current-state coverage recorded by the most recent inventory sync run.
|
- **FR-116v1-07 Coverage guard**: Compare MUST check current-state coverage recorded by the most recent inventory sync run.
|
||||||
- If effective scope contains policy types not present in coverage, the compare run MUST complete with warnings.
|
- If effective scope contains policy types not present in coverage, the compare run MUST complete with warnings.
|
||||||
@ -182,6 +191,7 @@ #### v1 — Meta-fidelity baseline compare (sellable)
|
|||||||
- Audit trail storage (canonical):
|
- Audit trail storage (canonical):
|
||||||
- Aggregations that do not fit `summary_counts` MUST be stored in `operation_runs.context` (not new summary keys).
|
- Aggregations that do not fit `summary_counts` MUST be stored in `operation_runs.context` (not new summary keys).
|
||||||
- Compare MUST store per-change-type counts in run context under `findings.counts_by_change_type` (e.g., keys: `missing_policy`, `unexpected_policy`, `different_version`).
|
- Compare MUST store per-change-type counts in run context under `findings.counts_by_change_type` (e.g., keys: `missing_policy`, `unexpected_policy`, `different_version`).
|
||||||
|
- For this repository, the canonical audit trail is the `operation_runs` record itself (status/outcome + context + numeric summary_counts); do not introduce parallel “audit summary” persistence for the same data.
|
||||||
- **FR-116v1-12 Drift UI context**: Compare run detail and drift landing MUST surface scope, coverage status, and fidelity (meta-based drift) and show a warning banner when coverage warnings were present.
|
- **FR-116v1-12 Drift UI context**: Compare run detail and drift landing MUST surface scope, coverage status, and fidelity (meta-based drift) and show a warning banner when coverage warnings were present.
|
||||||
|
|
||||||
#### v2 — Content-fidelity extension (deep drift, same engine)
|
#### v2 — Content-fidelity extension (deep drift, same engine)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ ## Phase 1: Setup (Shared Infrastructure)
|
|||||||
- [ ] T002 Run required agent context update via `.specify/scripts/bash/update-agent-context.sh copilot` (required by `specs/116-baseline-drift-engine/plan.md`)
|
- [ ] T002 Run required agent context update via `.specify/scripts/bash/update-agent-context.sh copilot` (required by `specs/116-baseline-drift-engine/plan.md`)
|
||||||
- [ ] T003 Ensure Sail + migrations are up for local validation (references `vendor/bin/sail`, `docker-compose.yml`, and `database/migrations/`)
|
- [ ] T003 Ensure Sail + migrations are up for local validation (references `vendor/bin/sail`, `docker-compose.yml`, and `database/migrations/`)
|
||||||
- [ ] T004 [P] Re-validate Spec 116 UI Action Matrix: confirm “no changes required” OR update the matrix table in `specs/116-baseline-drift-engine/spec.md`
|
- [ ] T004 [P] Re-validate Spec 116 UI Action Matrix: confirm “no changes required” OR update the matrix table in `specs/116-baseline-drift-engine/spec.md`
|
||||||
- [ ] T005 [P] Confirm supported policy types + foundations config sources match UI selectors (`config/tenantpilot.php` and `app/Support/Inventory/InventoryPolicyTypeMeta.php`)
|
- [ ] T005 [P] Document the mapping of “Policy Types” / “Foundations” selectors to config sources in `specs/116-baseline-drift-engine/plan.md` (and adjust `config/tenantpilot.php` / `app/Support/Inventory/InventoryPolicyTypeMeta.php` if mismatched)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -53,22 +53,23 @@ ### Tests for User Story 1 (write first)
|
|||||||
|
|
||||||
- [ ] T014 [P] [US1] Update capture tests for effective_scope recording + contract-based hashing in `tests/Feature/Baselines/BaselineCaptureTest.php`
|
- [ ] T014 [P] [US1] Update capture tests for effective_scope recording + contract-based hashing in `tests/Feature/Baselines/BaselineCaptureTest.php`
|
||||||
- [ ] T015 [P] [US1] Update compare findings tests to assert recurrence-key-based identity (no hashes in fingerprint) + lifecycle idempotency per run + `run.context.findings.counts_by_change_type` is present and accurate in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
- [ ] T015 [P] [US1] Update compare findings tests to assert recurrence-key-based identity (no hashes in fingerprint) + lifecycle idempotency per run + `run.context.findings.counts_by_change_type` is present and accurate in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
||||||
- [ ] T016 [P] [US1] Add/adjust preconditions tests for default baseline snapshot selection (latest successful snapshot) + explicit snapshot override (per `specs/116-baseline-drift-engine/contracts/openapi.yaml`) in `tests/Feature/Baselines/BaselineComparePreconditionsTest.php`
|
- [ ] T016 [P] [US1] Add unit test for InventoryMetaContract normalization stability (ordering, missing fields, nullability) in `tests/Unit/Baselines/InventoryMetaContractTest.php`
|
||||||
- [ ] T017 [P] [US1] Add test that re-capturing (new snapshot id) produces new finding identities (snapshot-scoped) in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
- [ ] T017 [P] [US1] Add/adjust preconditions tests for default snapshot selection via `baseline_profiles.active_snapshot_id` (“latest successful”) + explicit snapshot override (per `specs/116-baseline-drift-engine/contracts/openapi.yaml`) in `tests/Feature/Baselines/BaselineComparePreconditionsTest.php`
|
||||||
- [ ] T018 [P] [US1] Extend compare-start auth tests to cover positive + negative (403 for member missing `tenant.sync`, 404/redirect for missing tenant access) in `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`
|
- [ ] T018 [P] [US1] Add test that re-capturing (new snapshot id) produces new finding identities (snapshot-scoped) in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
||||||
- [ ] T019 [P] [US1] Add capture-start auth tests for Baseline Profile “Capture Snapshot” action (positive + negative manage capability, plus deny-as-not-found coverage via view route) in `tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php`
|
- [ ] T019 [P] [US1] Extend compare-start auth tests to cover: unauthenticated→302, authenticated non-member/not entitled tenant access→404, authenticated member missing `tenant.sync`→403, and success path in `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`
|
||||||
- [ ] T020 [P] [US1] Confirm baseline profile create/edit mutation surfaces have positive + negative authorization coverage; update for new scope shape if needed in `tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`
|
- [ ] T020 [P] [US1] Add capture-start auth tests for Baseline Profile “Capture Snapshot” action to cover: unauthenticated→302, authenticated non-member/not entitled workspace access→404, authenticated member missing `workspace_baselines.manage`→403, and success path in `tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php`
|
||||||
|
- [ ] T021 [P] [US1] Confirm baseline profile create/edit mutation surfaces have positive + negative authorization coverage (302/404/403 semantics) and update for new scope shape if needed in `tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`
|
||||||
|
|
||||||
### Implementation for User Story 1
|
### Implementation for User Story 1
|
||||||
|
|
||||||
- [ ] T021 [US1] Create + implement Inventory Meta Contract builder (normalized whitelist inputs; deterministic ordering) in `app/Services/Baselines/InventoryMetaContract.php`
|
- [ ] T022 [US1] Create + implement Inventory Meta Contract builder (normalized whitelist inputs; deterministic ordering) in `app/Services/Baselines/InventoryMetaContract.php`
|
||||||
- [ ] T022 [US1] Update snapshot hashing to hash ONLY the meta contract output (not entire meta_jsonb) in `app/Services/Baselines/BaselineSnapshotIdentity.php`
|
- [ ] T023 [US1] Update snapshot hashing to hash ONLY the meta contract output (not entire meta_jsonb) in `app/Services/Baselines/BaselineSnapshotIdentity.php`
|
||||||
- [ ] T023 [US1] Update baseline capture job to compute/store baseline_hash via InventoryMetaContract + record fidelity/meta observation evidence in `app/Jobs/CaptureBaselineSnapshotJob.php`
|
- [ ] T024 [US1] Update baseline capture job to compute/store `baseline_hash` via InventoryMetaContract and persist `meta_jsonb` evidence (`meta_contract`, `fidelity`, `source`, `observed_at`, `observed_operation_run_id`) in `app/Jobs/CaptureBaselineSnapshotJob.php`
|
||||||
- [ ] T024 [US1] Ensure capture OperationRun context records `effective_scope.*` (policy_types, foundation_types, all_types, foundations_included) in `app/Services/Baselines/BaselineCaptureService.php`
|
- [ ] T025 [US1] Ensure capture OperationRun context records `effective_scope.*` (policy_types, foundation_types, all_types, foundations_included) in `app/Services/Baselines/BaselineCaptureService.php`
|
||||||
- [ ] T025 [US1] Update baseline compare job to compute current_hash via InventoryMetaContract consistently with capture in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T026 [US1] Update baseline compare job to compute `current_hash` via InventoryMetaContract consistently with capture in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
- [ ] T026 [US1] Switch baseline-compare finding identity to recurrence key derived from (tenant, baseline_snapshot_id, policy_type, external_id, change_type) and set `fingerprint == recurrence_key` in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T027 [US1] Switch baseline-compare finding identity to recurrence key derived from (tenant, baseline_snapshot_id, policy_type, external_id, change_type) and set `fingerprint == recurrence_key` in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
- [ ] T027 [US1] Enforce per-run idempotency by using `findings.current_operation_run_id` (and/or evidence) so `times_seen` increments at most once per run identity in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T028 [US1] Enforce per-run idempotency by using `findings.current_operation_run_id` (and/or evidence) so `times_seen` increments at most once per run identity in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
- [ ] T028 [US1] Write compare audit context fields (baseline ids + `findings.counts_by_change_type`) onto the compare OperationRun context in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T029 [US1] Write compare audit context fields (baseline ids + `findings.counts_by_change_type`) onto the compare OperationRun context in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
|
|
||||||
**Checkpoint**: US1 tests pass: `vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineCaptureTest.php tests/Feature/Baselines/BaselineCompareFindingsTest.php tests/Feature/Baselines/BaselineComparePreconditionsTest.php`.
|
**Checkpoint**: US1 tests pass: `vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineCaptureTest.php tests/Feature/Baselines/BaselineCompareFindingsTest.php tests/Feature/Baselines/BaselineComparePreconditionsTest.php`.
|
||||||
|
|
||||||
@ -82,15 +83,15 @@ ## Phase 4: User Story 2 — Coverage warnings prevent misleading missing-policy
|
|||||||
|
|
||||||
### Tests for User Story 2 (write first)
|
### Tests for User Story 2 (write first)
|
||||||
|
|
||||||
- [ ] T029 [P] [US2] Extend inventory sync tests to assert per-type coverage payload is written to OperationRun context in `tests/Feature/Inventory/InventorySyncStartSurfaceTest.php`
|
- [ ] T030 [P] [US2] Extend inventory sync tests to assert per-type coverage payload is written to OperationRun context in `tests/Feature/Inventory/InventorySyncStartSurfaceTest.php`
|
||||||
- [ ] T030 [P] [US2] Create coverage-guard regression test: (a) uncovered types => no findings of any kind; (b) no completed inventory sync run / missing coverage payload => fail-safe zero findings; (c) effective scope expands to zero types => warnings + zero findings; outcome partially_succeeded; covered types still emit findings in `tests/Feature/Baselines/BaselineCompareCoverageGuardTest.php`
|
- [ ] T031 [P] [US2] Create coverage-guard regression test: (a) uncovered types => no findings of any kind; (b) no completed inventory sync run / missing coverage payload => fail-safe zero findings; (c) effective scope expands to zero types => warnings + zero findings; outcome partially_succeeded; covered types still emit findings in `tests/Feature/Baselines/BaselineCompareCoverageGuardTest.php`
|
||||||
|
|
||||||
### Implementation for User Story 2
|
### Implementation for User Story 2
|
||||||
|
|
||||||
- [ ] T031 [US2] Persist inventory sync coverage payload into latest inventory sync run context (`inventory.coverage.policy_types` + `inventory.coverage.foundation_types`) in `app/Services/Inventory/InventorySyncService.php`
|
- [ ] T032 [US2] Persist inventory sync coverage payload into latest inventory sync run context (`inventory.coverage.policy_types` + `inventory.coverage.foundation_types`) in `app/Services/Inventory/InventorySyncService.php`
|
||||||
- [ ] T032 [P] [US2] Create a small coverage parser/helper to normalize context payload for downstream consumers in `app/Support/Inventory/InventoryCoverage.php`
|
- [ ] T033 [P] [US2] Create a small coverage parser/helper to normalize context payload for downstream consumers in `app/Support/Inventory/InventoryCoverage.php`
|
||||||
- [ ] T033 [US2] Update baseline compare to read latest inventory sync run coverage, compute uncovered types, skip emission for uncovered types, and write coverage details into compare run context in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T034 [US2] Update baseline compare to read latest inventory sync run coverage, compute uncovered types, skip emission for uncovered types, and write coverage details into compare run context in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
- [ ] T034 [US2] Treat missing coverage proof (no completed inventory sync run, or unreadable/missing coverage payload) as uncovered-for-all-types (fail-safe): emit zero findings and mark outcome partially_succeeded (via OperationRunService), setting numeric summary_counts (including errors_recorded) using canonical keys only in `app/Jobs/CompareBaselineToTenantJob.php`
|
- [ ] T035 [US2] Treat missing coverage proof (no completed inventory sync run, or unreadable/missing coverage payload) as uncovered-for-all-types (fail-safe): emit zero findings and mark outcome partially_succeeded (via OperationRunService), setting numeric summary_counts (including errors_recorded) using canonical keys only in `app/Jobs/CompareBaselineToTenantJob.php`
|
||||||
|
|
||||||
**Note (canonical warning magnitude)**: For (c) “effective scope expands to zero types”, the compare MUST still surface a warning and therefore MUST set `summary_counts.errors_recorded = 1` (even though uncovered-types count is 0), to keep the warning visible under the numeric-only summary_counts contract.
|
**Note (canonical warning magnitude)**: For (c) “effective scope expands to zero types”, the compare MUST still surface a warning and therefore MUST set `summary_counts.errors_recorded = 1` (even though uncovered-types count is 0), to keep the warning visible under the numeric-only summary_counts contract.
|
||||||
|
|
||||||
@ -106,16 +107,16 @@ ## Phase 5: User Story 3 — Operators can understand scope, coverage, and fidel
|
|||||||
|
|
||||||
### Tests for User Story 3 (write first)
|
### Tests for User Story 3 (write first)
|
||||||
|
|
||||||
- [ ] T035 [P] [US3] Update Baseline Compare landing tests to cover warning/coverage state rendering inputs (stats DTO fields) in `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`
|
- [ ] T036 [P] [US3] Update Baseline Compare landing tests to cover warning/coverage state rendering inputs (stats DTO fields) in `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`
|
||||||
- [ ] T036 [P] [US3] Update drift landing comparison-info tests to include coverage/fidelity context when source is baseline compare in `tests/Feature/Drift/DriftLandingShowsComparisonInfoTest.php`
|
- [ ] T037 [P] [US3] Update drift landing comparison-info tests to include coverage/fidelity context when source is baseline compare in `tests/Feature/Drift/DriftLandingShowsComparisonInfoTest.php`
|
||||||
|
|
||||||
### Implementation for User Story 3
|
### Implementation for User Story 3
|
||||||
|
|
||||||
- [ ] T037 [US3] Extend BaselineCompareStats DTO to include coverage status + uncovered types summary + fidelity indicator sourced from latest compare run context in `app/Support/Baselines/BaselineCompareStats.php`
|
- [ ] T038 [US3] Extend BaselineCompareStats DTO to include coverage status + uncovered types summary + fidelity indicator sourced from latest compare run context in `app/Support/Baselines/BaselineCompareStats.php`
|
||||||
- [ ] T038 [US3] Wire new stats fields into the BaselineCompareLanding Livewire page state in `app/Filament/Pages/BaselineCompareLanding.php`
|
- [ ] T039 [US3] Wire new stats fields into the BaselineCompareLanding Livewire page state in `app/Filament/Pages/BaselineCompareLanding.php`
|
||||||
- [ ] T039 [US3] Render coverage badge + warning banner + fidelity label on the landing view in `resources/views/filament/pages/baseline-compare-landing.blade.php`
|
- [ ] T040 [US3] Render coverage badge + warning banner + fidelity label on the landing view in `resources/views/filament/pages/baseline-compare-landing.blade.php`
|
||||||
- [ ] T040 [US3] Add a findings-list banner when latest baseline compare run had uncovered types (linking to the run) in `app/Filament/Resources/FindingResource/Pages/ListFindings.php`
|
- [ ] T041 [US3] Add a findings-list banner when latest baseline compare run had uncovered types (linking to the run) in `app/Filament/Resources/FindingResource/Pages/ListFindings.php`
|
||||||
- [ ] T041 [US3] Ensure run detail already shows context; if needed, add baseline compare “Coverage” summary entry for readability in `app/Filament/Resources/OperationRunResource.php`
|
- [ ] T042 [US3] Ensure run detail already shows context; if needed, add baseline compare “Coverage” summary entry for readability in `app/Filament/Resources/OperationRunResource.php`
|
||||||
|
|
||||||
**Checkpoint**: US3 tests pass: `vendor/bin/sail artisan test --compact tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php tests/Feature/Drift/DriftLandingShowsComparisonInfoTest.php`.
|
**Checkpoint**: US3 tests pass: `vendor/bin/sail artisan test --compact tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php tests/Feature/Drift/DriftLandingShowsComparisonInfoTest.php`.
|
||||||
|
|
||||||
@ -125,19 +126,19 @@ ## Phase 6: Polish & Cross-Cutting Concerns
|
|||||||
|
|
||||||
**Purpose**: Preserve operability semantics (auto-close, stats), Ops-UX compliance, and fast regression feedback.
|
**Purpose**: Preserve operability semantics (auto-close, stats), Ops-UX compliance, and fast regression feedback.
|
||||||
|
|
||||||
- [ ] T042 Confirm baseline compare stats remain profile-grouped via `scope_key = baseline_profile:{id}` after identity change in `app/Support/Baselines/BaselineCompareStats.php`
|
- [ ] T043 Confirm baseline compare stats remain profile-grouped via `scope_key = baseline_profile:{id}` after identity change in `app/Support/Baselines/BaselineCompareStats.php`
|
||||||
- [ ] T043 Ensure baseline auto-close behavior still works with snapshot-scoped identities (no stale open findings after successful compare) in `app/Services/Baselines/BaselineAutoCloseService.php`
|
- [ ] T044 Ensure baseline auto-close behavior still works with snapshot-scoped identities (no stale open findings after successful compare) in `app/Services/Baselines/BaselineAutoCloseService.php`
|
||||||
- [ ] T044 [P] Update/verify auto-close regression test remains valid after identity change in `tests/Feature/Baselines/BaselineOperabilityAutoCloseTest.php`
|
- [ ] T045 [P] Update/verify auto-close regression test remains valid after identity change in `tests/Feature/Baselines/BaselineOperabilityAutoCloseTest.php`
|
||||||
- [ ] T045 [P] Add/extend guard test asserting OperationRun summary_counts are numeric-only and keys are limited to `OperationSummaryKeys::all()` for baseline capture/compare runs in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
- [ ] T046 [P] Add/extend guard test asserting OperationRun summary_counts are numeric-only and keys are limited to `OperationSummaryKeys::all()` for baseline capture/compare runs in `tests/Feature/Baselines/BaselineCompareFindingsTest.php`
|
||||||
- [ ] T046 [P] Add Spec 116 “One engine” regression guard to prevent legacy compare/hash paths (no `DriftHasher::fingerprint()` use for baseline compare; capture/compare hashing flows through `InventoryMetaContract`) in `tests/Feature/Guards/Spec116OneEngineGuardTest.php`
|
- [ ] T047 [P] Add Spec 116 “One engine” regression guard to prevent legacy compare/hash paths (no `DriftHasher::fingerprint()` use for baseline compare; capture/compare hashing flows through `InventoryMetaContract`) in `tests/Feature/Guards/Spec116OneEngineGuardTest.php`
|
||||||
- [ ] T047 [P] Add Spec 116 performance regression guard (compare is DB-only; no Graph/hydration calls; compare processes snapshot + inventory via chunking) in `tests/Feature/Baselines/BaselineComparePerformanceGuardTest.php`
|
- [ ] T048 [P] Add Spec 116 performance regression guard (compare is DB-only; no Graph/hydration calls; compare processes snapshot + inventory via chunking) in `tests/Feature/Baselines/BaselineComparePerformanceGuardTest.php`
|
||||||
- [ ] T048 [P] Ensure OPS-UX-GUARD-001 coverage is enforced for this feature by running/updating constitution guards in `tests/Feature/OpsUx/Constitution/DirectStatusTransitionGuardTest.php`, `tests/Feature/OpsUx/Constitution/JobDbNotificationGuardTest.php`, and `tests/Feature/OpsUx/Constitution/LegacyNotificationGuardTest.php`
|
- [ ] T049 [P] Verify OPS-UX-GUARD-001 remains satisfied for Spec 116 code paths; if guard tests fail, fix code (preferred) or update guard expectations intentionally in `tests/Feature/OpsUx/Constitution/DirectStatusTransitionGuardTest.php`, `tests/Feature/OpsUx/Constitution/JobDbNotificationGuardTest.php`, and `tests/Feature/OpsUx/Constitution/LegacyNotificationGuardTest.php`
|
||||||
- [ ] T049 [P] Create Baseline Profile archive action tests (confirmation required + RBAC 403/404 semantics + success path) in `tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`
|
- [ ] T050 [P] Create Baseline Profile archive action tests (confirmation required + RBAC 403/404 semantics + success path) in `tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`
|
||||||
- [ ] T050 [P] Ensure archive action is declared in Action Surface slots and remains “More” row action only (max 2 visible row actions) in `tests/Feature/Guards/ActionSurfaceContractTest.php`
|
- [ ] T051 [P] Ensure archive action is declared in Action Surface slots and remains “More” row action only (max 2 visible row actions) in `tests/Feature/Guards/ActionSurfaceContractTest.php`
|
||||||
- [ ] T051 Run baseline-focused test pack for Spec 116: `vendor/bin/sail artisan test --compact tests/Feature/Baselines/` (references `tests/Feature/Baselines/`)
|
- [ ] T052 Run baseline-focused test pack for Spec 116: `vendor/bin/sail artisan test --compact tests/Feature/Baselines/` (references `tests/Feature/Baselines/`)
|
||||||
- [ ] T052 Run Ops-UX guard test pack: `vendor/bin/sail artisan test --compact --group=ops-ux` (references `tests/Feature/OpsUx/Constitution/`)
|
- [ ] T053 Run Ops-UX guard test pack: `vendor/bin/sail artisan test --compact --group=ops-ux` (references `tests/Feature/OpsUx/Constitution/`)
|
||||||
- [ ] T053 Run Pint formatter on changed files: `vendor/bin/sail pint --dirty --format agent` (references `app/` and `tests/`)
|
- [ ] T054 Run Pint formatter on changed files: `vendor/bin/sail pint --dirty --format agent` (references `app/` and `tests/`)
|
||||||
- [ ] T054 Validate developer quickstart still matches real behavior (update if needed) in `specs/116-baseline-drift-engine/quickstart.md`
|
- [ ] T055 Validate developer quickstart still matches real behavior (update if needed) in `specs/116-baseline-drift-engine/quickstart.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user