TenantAtlas/apps/platform/tests/Feature/Guards/TestLaneRecalibrationPolicyTest.php
ahmido 81a07a41e4
Some checks failed
Main Confidence / confidence (push) Failing after 46s
feat: implement runtime trend recalibration reporting (#244)
## Summary
- implement Spec 211 runtime trend reporting with bounded lane history, drift classification, hotspot trend output, and recalibration evidence handling
- extend the repo-truth governance seams and workflow wrappers for comparable-bundle hydration, trend artifact publication, and contract-backed reporting
- add the Spec 211 planning artifacts, data model, quickstart, tasks, and repository contract documents

## Validation
- parsed `specs/211-runtime-trend-recalibration/contracts/test-runtime-trend-history.schema.json`
- parsed `specs/211-runtime-trend-recalibration/contracts/test-runtime-trend.logical.openapi.yaml`
- re-ran cross-artifact consistency analysis for the Spec 211 artifact set until no material findings remained
- no application test suite was re-run as part of this final commit/push/PR step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #244
2026-04-18 07:36:05 +00:00

112 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
use Tests\Support\TestLaneBudget;
use Tests\Support\TestLaneTrendFixtures;
function recalibrationEvidenceHistory(string $laneId, int $count): array
{
$report = TestLaneTrendFixtures::buildReport(
laneId: $laneId,
wallClockSeconds: $laneId === 'confidence' ? 438.0 : 188.0,
durationsByFile: [
'tests/Feature/Guards/TestLaneRecalibrationPolicyTest.php' => 12.0,
],
ciContext: [
'workflowId' => $laneId === 'confidence' ? 'main-confidence' : 'pr-fast-feedback',
'triggerClass' => $laneId === 'confidence' ? 'mainline-push' : 'pull-request',
'entryPointResolved' => true,
'workflowLaneMatched' => true,
],
comparisonProfile: in_array($laneId, ['fast-feedback', 'confidence'], true) ? 'shared-test-fixture-slimming' : null,
);
$templateRecord = $report['trendHistoryArtifact']['history'][0];
return array_values(array_map(
static function (int $index) use ($templateRecord): array {
$record = $templateRecord;
$record['runRef'] = sprintf('%s-evidence-%d', $templateRecord['laneId'], $index + 1);
$record['generatedAt'] = sprintf('2026-04-%02dT10:00:00+00:00', $index + 1);
return $record;
},
range(0, $count - 1),
));
}
it('keeps baseline and budget recalibration rules separate and enforces the stronger budget evidence window', function (): void {
$assessment = [
'recalibrationRecommendation' => 'review-baseline',
];
$baselineHistory = recalibrationEvidenceHistory('fast-feedback', 3);
$budgetHistory = recalibrationEvidenceHistory('confidence', 5);
$baselineDecision = TestLaneBudget::buildRecalibrationDecisionRecord(
laneId: 'fast-feedback',
targetType: 'baseline',
assessment: $assessment,
historyRecords: $baselineHistory,
decisionStatus: 'approved',
rationaleCode: 'lane-scope-change',
recordedIn: 'specs/211-runtime-trend-recalibration/spec.md',
proposedValueSeconds: 184.0,
);
$budgetDecision = TestLaneBudget::buildRecalibrationDecisionRecord(
laneId: 'confidence',
targetType: 'budget',
assessment: ['recalibrationRecommendation' => 'review-budget'],
historyRecords: $budgetHistory,
decisionStatus: 'approved',
rationaleCode: 'sustained-erosion',
recordedIn: 'specs/211-runtime-trend-recalibration/spec.md',
proposedValueSeconds: 470.0,
);
expect($baselineDecision['targetType'])->toBe('baseline')
->and($baselineDecision['decisionStatus'])->toBe('approved')
->and($budgetDecision['targetType'])->toBe('budget')
->and($budgetDecision['decisionStatus'])->toBe('approved')
->and($budgetDecision['evidenceRunRefs'])->toHaveCount(5);
expect(static fn () => TestLaneBudget::buildRecalibrationDecisionRecord(
laneId: 'confidence',
targetType: 'budget',
assessment: ['recalibrationRecommendation' => 'review-budget'],
historyRecords: recalibrationEvidenceHistory('confidence', 4),
decisionStatus: 'approved',
rationaleCode: 'sustained-erosion',
recordedIn: 'specs/211-runtime-trend-recalibration/spec.md',
proposedValueSeconds: 470.0,
))->toThrow(InvalidArgumentException::class);
});
it('requires approved versus rejected rationale handling that matches the policy', function (): void {
$history = recalibrationEvidenceHistory('fast-feedback', 3);
$rejectedDecision = TestLaneBudget::buildRecalibrationDecisionRecord(
laneId: 'fast-feedback',
targetType: 'budget',
assessment: ['recalibrationRecommendation' => 'investigate'],
historyRecords: [$history[0]],
decisionStatus: 'rejected',
rationaleCode: 'noise-rejected',
recordedIn: 'specs/211-runtime-trend-recalibration/spec.md',
);
expect($rejectedDecision['decisionStatus'])->toBe('rejected')
->and($rejectedDecision['rationaleCode'])->toBe('noise-rejected');
expect(static fn () => TestLaneBudget::buildRecalibrationDecisionRecord(
laneId: 'fast-feedback',
targetType: 'baseline',
assessment: ['recalibrationRecommendation' => 'review-baseline'],
historyRecords: $history,
decisionStatus: 'approved',
rationaleCode: 'sustained-erosion',
recordedIn: 'specs/211-runtime-trend-recalibration/spec.md',
proposedValueSeconds: 184.0,
))->toThrow(InvalidArgumentException::class);
});