Some checks failed
Main Confidence / confidence (push) Failing after 3m36s
## Summary - add explicit Gitea workflow files for PR Fast Feedback, `dev` Confidence, Heavy Governance, and Browser lanes - extend the repo-truth lane support seams with workflow profiles, trigger-aware budget enforcement, artifact publication contracts, CI summaries, and failure classification - add deterministic artifact staging, new CI governance guard coverage, and Spec 210 planning/contracts/docs updates ## Validation - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/CiFastFeedbackWorkflowContractTest.php tests/Feature/Guards/CiConfidenceWorkflowContractTest.php tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php tests/Feature/Guards/CiLaneFailureClassificationContractTest.php tests/Feature/Guards/FastFeedbackLaneContractTest.php tests/Feature/Guards/ConfidenceLaneContractTest.php tests/Feature/Guards/HeavyGovernanceLaneContractTest.php tests/Feature/Guards/BrowserLaneIsolationTest.php tests/Feature/Guards/FixtureLaneImpactBudgetTest.php tests/Feature/Guards/TestLaneManifestTest.php tests/Feature/Guards/TestLaneArtifactsContractTest.php tests/Feature/Guards/TestLaneCommandContractTest.php` - `./scripts/platform-test-lane fast-feedback` - `./scripts/platform-test-lane confidence` - `./scripts/platform-test-lane heavy-governance` - `./scripts/platform-test-lane browser` - `./scripts/platform-test-report fast-feedback` - `./scripts/platform-test-report confidence` ## Notes - scheduled Heavy Governance and Browser workflows stay gated behind `TENANTATLAS_ENABLE_HEAVY_GOVERNANCE_SCHEDULE=1` and `TENANTATLAS_ENABLE_BROWSER_SCHEDULE=1` - the remaining rollout evidence task is capturing the live Gitea run set this PR enables: PR Fast Feedback, `dev` Confidence, manual and scheduled Heavy Governance, and manual and scheduled Browser runs Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #243
190 lines
7.9 KiB
PHP
190 lines
7.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Tests\Support\TestLaneManifest;
|
|
use Tests\Support\TestLaneReport;
|
|
|
|
function heavyGovernanceSyntheticHotspots(): array
|
|
{
|
|
return [
|
|
['file' => 'tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php', 'seconds' => 22.4],
|
|
['file' => 'tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php', 'seconds' => 21.1],
|
|
['file' => 'tests/Feature/Filament/BaselineActionAuthorizationTest.php', 'seconds' => 19.5],
|
|
['file' => 'tests/Feature/Findings/FindingBulkActionsTest.php', 'seconds' => 18.2],
|
|
['file' => 'tests/Feature/Findings/FindingWorkflowRowActionsTest.php', 'seconds' => 14.8],
|
|
['file' => 'tests/Feature/Findings/FindingWorkflowViewActionsTest.php', 'seconds' => 13.6],
|
|
['file' => 'tests/Feature/SettingsFoundation/WorkspaceSettingsManageTest.php', 'seconds' => 12.7],
|
|
['file' => 'tests/Feature/Guards/ActionSurfaceContractTest.php', 'seconds' => 11.9],
|
|
['file' => 'tests/Feature/Guards/OperationLifecycleOpsUxGuardTest.php', 'seconds' => 10.4],
|
|
['file' => 'tests/Feature/Filament/PolicyResourceAdminSearchParityTest.php', 'seconds' => 4.2],
|
|
];
|
|
}
|
|
|
|
it('keeps lane artifact paths app-root relative under storage/logs/test-lanes', function (): void {
|
|
$artifacts = TestLaneReport::artifactPaths('fast-feedback');
|
|
$artifactContract = TestLaneManifest::artifactPublicationContract('fast-feedback');
|
|
|
|
expect($artifacts)->toHaveKeys(['junit', 'summary', 'budget', 'report', 'profile']);
|
|
|
|
expect($artifactContract['requiredFiles'])->toEqualCanonicalizing(['summary.md', 'budget.json', 'report.json', 'junit.xml'])
|
|
->and($artifactContract['stagedNamePattern'])->toBe('{laneId}.{artifactFile}');
|
|
|
|
foreach (array_values($artifacts) as $relativePath) {
|
|
expect($relativePath)->toStartWith('storage/logs/test-lanes/');
|
|
}
|
|
});
|
|
|
|
it('keeps only the skeleton file checked into the lane artifact directory', function (): void {
|
|
$gitignore = base_path('storage/logs/test-lanes/.gitignore');
|
|
|
|
expect(file_exists($gitignore))->toBeTrue()
|
|
->and((string) file_get_contents($gitignore))->toContain('*')
|
|
->and((string) file_get_contents($gitignore))->toContain('!.gitignore');
|
|
});
|
|
|
|
it('publishes heavy attribution, contract, and coverage payloads under the canonical artifact root', function (): void {
|
|
$durationsByFile = collect(heavyGovernanceSyntheticHotspots())
|
|
->mapWithKeys(static fn (array $entry): array => [$entry['file'] => $entry['seconds']])
|
|
->all();
|
|
|
|
$slowestEntries = collect(heavyGovernanceSyntheticHotspots())
|
|
->map(static fn (array $entry): array => [
|
|
'label' => $entry['file'].'::synthetic',
|
|
'subject' => $entry['file'].'::synthetic',
|
|
'filePath' => $entry['file'],
|
|
'durationSeconds' => $entry['seconds'],
|
|
'wallClockSeconds' => $entry['seconds'],
|
|
'laneId' => 'heavy-governance',
|
|
])
|
|
->values()
|
|
->all();
|
|
|
|
$report = TestLaneReport::buildReport(
|
|
laneId: 'heavy-governance',
|
|
wallClockSeconds: 118.4,
|
|
slowestEntries: $slowestEntries,
|
|
durationsByFile: $durationsByFile,
|
|
);
|
|
|
|
expect($report['artifactDirectory'])->toBe('storage/logs/test-lanes')
|
|
->and($report['slowestEntries'])->toHaveCount(10)
|
|
->and($report)->toHaveKeys([
|
|
'artifactPublicationContract',
|
|
'knownWorkflowProfiles',
|
|
'failureClasses',
|
|
'budgetContract',
|
|
'hotspotInventory',
|
|
'decompositionRecords',
|
|
'slimmingDecisions',
|
|
'authorGuidance',
|
|
'inventoryCoverage',
|
|
'budgetSnapshots',
|
|
'budgetOutcome',
|
|
'remainingOpenFamilies',
|
|
'stabilizedFamilies',
|
|
])
|
|
->and(collect($report['classificationAttribution'])->pluck('classificationId')->all())
|
|
->toContain('ui-workflow', 'surface-guard', 'discovery-heavy')
|
|
->and(collect($report['familyAttribution'])->pluck('familyId')->all())
|
|
->toContain(
|
|
'baseline-profile-start-surfaces',
|
|
'findings-workflow-surfaces',
|
|
'finding-bulk-actions-workflow',
|
|
'workspace-settings-slice-management',
|
|
'action-surface-contract',
|
|
'ops-ux-governance',
|
|
)
|
|
->and(collect($report['budgetEvaluations'])->pluck('targetType')->unique()->values()->all())
|
|
->toEqualCanonicalizing(['lane', 'classification', 'family'])
|
|
->and($report['familyBudgetEvaluations'])->not->toBeEmpty()
|
|
->and($report['inventoryCoverage']['meetsInclusionRule'])->toBeTrue()
|
|
->and($report['inventoryCoverage']['inventoryFamilyCount'])->toBe(6)
|
|
->and($report['budgetSnapshots'])->toHaveCount(2)
|
|
->and($report['budgetOutcome'])->toHaveKeys([
|
|
'decisionStatus',
|
|
'finalThresholdSeconds',
|
|
'remainingOpenFamilies',
|
|
'followUpDebt',
|
|
])
|
|
->and($report['knownWorkflowProfiles'])->toContain('heavy-governance-manual', 'heavy-governance-scheduled');
|
|
});
|
|
|
|
it('stages deterministic CI artifact bundles from the canonical lane outputs', function (): void {
|
|
$artifactDirectory = 'storage/logs/test-lanes/contract-stage-test';
|
|
$stagingDirectory = base_path('storage/logs/test-lanes/contract-stage-test/staged');
|
|
$report = TestLaneReport::buildReport(
|
|
laneId: 'fast-feedback',
|
|
wallClockSeconds: 182.4,
|
|
slowestEntries: [],
|
|
durationsByFile: [],
|
|
artifactDirectory: $artifactDirectory,
|
|
ciContext: [
|
|
'workflowId' => 'pr-fast-feedback',
|
|
'triggerClass' => 'pull-request',
|
|
'entryPointResolved' => true,
|
|
'workflowLaneMatched' => true,
|
|
],
|
|
);
|
|
|
|
TestLaneReport::writeArtifacts(
|
|
laneId: 'fast-feedback',
|
|
report: $report,
|
|
profileOutput: null,
|
|
artifactDirectory: $artifactDirectory,
|
|
exitCode: 0,
|
|
);
|
|
|
|
$artifactPaths = TestLaneReport::artifactPaths('fast-feedback', $artifactDirectory);
|
|
|
|
file_put_contents(
|
|
TestLaneManifest::absolutePath($artifactPaths['junit']),
|
|
<<<'XML'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<testsuites>
|
|
<testsuite name="fast-feedback" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.1">
|
|
<testcase name="synthetic" file="tests/Feature/Guards/TestLaneArtifactsContractTest.php" time="0.1" />
|
|
</testsuite>
|
|
</testsuites>
|
|
XML,
|
|
);
|
|
|
|
$stagingResult = TestLaneReport::stageArtifacts(
|
|
laneId: 'fast-feedback',
|
|
stagingDirectory: $stagingDirectory,
|
|
artifactDirectory: $artifactDirectory,
|
|
);
|
|
|
|
expect($stagingResult['complete'])->toBeTrue()
|
|
->and(collect($stagingResult['stagedArtifacts'])->pluck('artifactType')->all())
|
|
->toEqualCanonicalizing(['summary.md', 'budget.json', 'report.json', 'junit.xml'])
|
|
->and(collect($stagingResult['stagedArtifacts'])->pluck('relativePath')->all())
|
|
->toContain(
|
|
$stagingDirectory.'/fast-feedback.summary.md',
|
|
$stagingDirectory.'/fast-feedback.budget.json',
|
|
$stagingDirectory.'/fast-feedback.report.json',
|
|
$stagingDirectory.'/fast-feedback.junit.xml',
|
|
);
|
|
});
|
|
|
|
|
|
it('publishes the shared fixture slimming comparison only for the governed standard lanes', function (): void {
|
|
$fastFeedback = TestLaneReport::buildReport(
|
|
laneId: 'fast-feedback',
|
|
wallClockSeconds: 176.73623,
|
|
slowestEntries: [],
|
|
durationsByFile: [],
|
|
comparisonProfile: 'shared-test-fixture-slimming',
|
|
);
|
|
|
|
$heavyGovernance = TestLaneReport::buildReport(
|
|
laneId: 'heavy-governance',
|
|
wallClockSeconds: 83.66,
|
|
slowestEntries: [],
|
|
durationsByFile: [],
|
|
comparisonProfile: 'shared-test-fixture-slimming',
|
|
);
|
|
|
|
expect($fastFeedback)->toHaveKey('sharedFixtureSlimmingComparison')
|
|
->and($heavyGovernance)->not->toHaveKey('sharedFixtureSlimmingComparison');
|
|
});
|