Skip to content

Commit e48ac38

Browse files
Collapse visibility filters to the clean-slate v2 contract
Collapse visibility filter contract to current v2 version
1 parent d91dee2 commit e48ac38

3 files changed

Lines changed: 20 additions & 156 deletions

File tree

src/V2/Support/VisibilityFilters.php

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ final class VisibilityFilters
1313
{
1414
public const VERSION = 6;
1515

16-
public const MINIMUM_SUPPORTED_VERSION = 1;
17-
1816
private const FIELD_LABELS = [
1917
'instance_id' => 'Instance ID',
2018
'run_id' => 'Run ID',
@@ -83,87 +81,21 @@ final class VisibilityFilters
8381

8482
private const LABEL_KEY_PATTERN = '/^[A-Za-z0-9_.:-]{1,64}$/';
8583

86-
private const DEPRECATED_VERSIONS = [1, 2];
87-
8884
private const RESERVED_VIEW_ID_PREFIX = 'system:';
8985

9086
/**
9187
* @return list<int>
9288
*/
9389
public static function supportedVersions(): array
9490
{
95-
return [1, 2, 3, 4, 5, self::VERSION];
96-
}
97-
98-
public static function minimumSupportedVersion(): int
99-
{
100-
return self::MINIMUM_SUPPORTED_VERSION;
101-
}
102-
103-
public static function isDeprecated(int $version): bool
104-
{
105-
return in_array($version, self::DEPRECATED_VERSIONS, true);
91+
return [self::VERSION];
10692
}
10793

10894
public static function isReservedViewId(string $id): bool
10995
{
11096
return str_starts_with($id, self::RESERVED_VIEW_ID_PREFIX);
11197
}
11298

113-
/**
114-
* @return array{
115-
* current_version: int,
116-
* minimum_supported_version: int,
117-
* supported_versions: list<int>,
118-
* deprecated_versions: list<int>,
119-
* reserved_view_id_prefix: string,
120-
* upgrade_policy: string
121-
* }
122-
*/
123-
public static function versionEvolutionPolicy(): array
124-
{
125-
return [
126-
'current_version' => self::VERSION,
127-
'minimum_supported_version' => self::MINIMUM_SUPPORTED_VERSION,
128-
'supported_versions' => self::supportedVersions(),
129-
'deprecated_versions' => self::DEPRECATED_VERSIONS,
130-
'reserved_view_id_prefix' => self::RESERVED_VIEW_ID_PREFIX,
131-
'upgrade_policy' => 'Saved views written against any supported version remain readable. '
132-
. 'Updating a saved view rewrites it onto the current version. '
133-
. 'Deprecated versions are still loadable but should be migrated to the current version. '
134-
. 'Versions below the minimum supported version are rejected.',
135-
];
136-
}
137-
138-
/**
139-
* Machine-readable policy describing how visibility filters behave when
140-
* workers run different package versions concurrently and when projection
141-
* rebuilds are authoritative for derived filter fields.
142-
*
143-
* @return array<string, mixed>
144-
*/
145-
public static function mixedFleetPolicy(): array
146-
{
147-
return [
148-
'projection_schema_version' => RunSummaryProjector::SCHEMA_VERSION,
149-
'filter_version' => self::VERSION,
150-
'invariants' => [
151-
'Filter normalization is idempotent regardless of the worker package version that wrote the summary projection.',
152-
'Summaries projected by older workers may have NULL for fields added in later schema versions; exact-match filters will not match NULL, so those rows are excluded from filtered views until re-projected.',
153-
'The rebuild-projections command re-projects from durable runtime state, filling in any derived fields missing from older schema versions.',
154-
'Saved views remain readable across filter version bumps; updating a deprecated saved view rewrites it onto the current version.',
155-
'Boolean and base string filter fields use exact-match semantics; explicit *_contains string filters use escaped SQL LIKE substring matching on the run-summary projection.',
156-
],
157-
'projection_backfill_authority' => [
158-
'trigger' => 'Summaries with a NULL or lower projection_schema_version than the current build need re-projection.',
159-
'mechanism' => 'workflow:v2:rebuild-projections --needs-rebuild detects schema-outdated rows and re-projects them from durable state.',
160-
'scope' => 'Re-projection populates all current derived fields including namespace, search_attributes, visibility_labels, liveness_state, wait_kind, repair_blocked_reason, task_problem, and history budget.',
161-
'safety' => 'Re-projection is idempotent. Running it on an already-current row produces the same output.',
162-
],
163-
'upgrade_path' => 'Deploy the new package version to all workers, then run workflow:v2:rebuild-projections --needs-rebuild to backfill schema-outdated summaries. Mixed-fleet operation is safe during the rollout window — older workers continue projecting with their schema version, and the rebuild command brings all rows to the current schema after rollout completes.',
164-
];
165-
}
166-
16799
/**
168100
* @return array<int, string>
169101
*/
@@ -202,9 +134,7 @@ public static function definition(): array
202134

203135
return [
204136
'version' => self::VERSION,
205-
'minimum_supported_version' => self::MINIMUM_SUPPORTED_VERSION,
206137
'supported_versions' => self::supportedVersions(),
207-
'deprecated_versions' => self::DEPRECATED_VERSIONS,
208138
'reserved_view_id_prefix' => self::RESERVED_VIEW_ID_PREFIX,
209139
'fields' => $fields,
210140
'labels' => [
@@ -243,7 +173,6 @@ public static function definition(): array
243173
* @return array{
244174
* version: int|null,
245175
* current_version: int,
246-
* minimum_supported_version: int,
247176
* supported_versions: list<int>,
248177
* supported: bool,
249178
* deprecated: bool,
@@ -256,29 +185,21 @@ public static function versionMetadata(mixed $version): array
256185
$normalizedVersion = self::normalizeVersion($version);
257186
$supportedVersions = self::supportedVersions();
258187
$supported = $normalizedVersion !== null && in_array($normalizedVersion, $supportedVersions, true);
259-
$deprecated = $supported && self::isDeprecated($normalizedVersion);
260188

261189
$status = match (true) {
262190
! $supported => 'unsupported',
263-
$deprecated => 'deprecated',
264191
default => 'supported',
265192
};
266193

267194
return [
268195
'version' => $normalizedVersion,
269196
'current_version' => self::VERSION,
270-
'minimum_supported_version' => self::MINIMUM_SUPPORTED_VERSION,
271197
'supported_versions' => $supportedVersions,
272198
'supported' => $supported,
273-
'deprecated' => $deprecated,
199+
'deprecated' => false,
274200
'status' => $status,
275201
'message' => match (true) {
276202
! $supported => self::unsupportedVersionMessage($normalizedVersion, $supportedVersions),
277-
$deprecated => sprintf(
278-
'This saved view uses deprecated visibility filter version %d. Consider updating it to the current version %d.',
279-
$normalizedVersion,
280-
self::VERSION,
281-
),
282203
default => null,
283204
},
284205
];

tests/Feature/V2/V2SearchAttributeTest.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,6 @@ public function testVisibilityFiltersDefinitionIncludesSearchAttributes(): void
175175
public function testVisibilityFilterVersionIsUpdated(): void
176176
{
177177
$this->assertSame(6, VisibilityFilters::VERSION);
178-
$this->assertContains(6, VisibilityFilters::supportedVersions());
179-
$this->assertContains(5, VisibilityFilters::supportedVersions());
180-
$this->assertContains(3, VisibilityFilters::supportedVersions());
178+
$this->assertSame([6], VisibilityFilters::supportedVersions());
181179
}
182180
}

tests/Unit/V2/VisibilityFiltersTest.php

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ public function testDefinitionDescribesExactVisibilityContract(): void
322322
$definition = VisibilityFilters::definition();
323323

324324
$this->assertSame(VisibilityFilters::VERSION, $definition['version']);
325-
$this->assertSame([1, 2, 3, 4, 5, VisibilityFilters::VERSION], $definition['supported_versions']);
325+
$this->assertSame([VisibilityFilters::VERSION], $definition['supported_versions']);
326326
$this->assertSame('Instance ID', $definition['fields']['instance_id']['label']);
327327
$this->assertSame('string', $definition['fields']['instance_id']['type']);
328328
$this->assertSame('text', $definition['fields']['instance_id']['input']);
@@ -493,68 +493,37 @@ public function testVersionMetadataMarksUnsupportedSavedViewContractsExplicitly(
493493

494494
$this->assertSame(VisibilityFilters::VERSION, $supported['version']);
495495
$this->assertSame(VisibilityFilters::VERSION, $supported['current_version']);
496-
$this->assertSame(VisibilityFilters::MINIMUM_SUPPORTED_VERSION, $supported['minimum_supported_version']);
497-
$this->assertSame([1, 2, 3, 4, 5, VisibilityFilters::VERSION], $supported['supported_versions']);
496+
$this->assertSame([VisibilityFilters::VERSION], $supported['supported_versions']);
498497
$this->assertTrue($supported['supported']);
499498
$this->assertFalse($supported['deprecated']);
500499
$this->assertSame('supported', $supported['status']);
501500
$this->assertNull($supported['message']);
502501

503502
$this->assertSame(99, $unsupported['version']);
504503
$this->assertSame(VisibilityFilters::VERSION, $unsupported['current_version']);
505-
$this->assertSame(VisibilityFilters::MINIMUM_SUPPORTED_VERSION, $unsupported['minimum_supported_version']);
506-
$this->assertSame([1, 2, 3, 4, 5, VisibilityFilters::VERSION], $unsupported['supported_versions']);
504+
$this->assertSame([VisibilityFilters::VERSION], $unsupported['supported_versions']);
507505
$this->assertFalse($unsupported['supported']);
508506
$this->assertFalse($unsupported['deprecated']);
509507
$this->assertSame('unsupported', $unsupported['status']);
510508
$this->assertSame(
511-
'This saved view uses visibility filter version 99, but this Waterline build supports version 1, 2, 3, 4, 5, 6.',
509+
'This saved view uses visibility filter version 99, but this Waterline build supports version 6.',
512510
$unsupported['message'],
513511
);
514512
}
515513

516-
public function testVersionMetadataMarksDeprecatedVersionsExplicitly(): void
514+
public function testVersionMetadataRejectsPreStableV2AlphaVersions(): void
517515
{
518-
$deprecated = VisibilityFilters::versionMetadata(1);
516+
$alphaVersion = VisibilityFilters::versionMetadata(1);
519517

520-
$this->assertSame(1, $deprecated['version']);
521-
$this->assertSame(VisibilityFilters::VERSION, $deprecated['current_version']);
522-
$this->assertTrue($deprecated['supported']);
523-
$this->assertTrue($deprecated['deprecated']);
524-
$this->assertSame('deprecated', $deprecated['status']);
518+
$this->assertSame(1, $alphaVersion['version']);
519+
$this->assertSame(VisibilityFilters::VERSION, $alphaVersion['current_version']);
520+
$this->assertFalse($alphaVersion['supported']);
521+
$this->assertFalse($alphaVersion['deprecated']);
522+
$this->assertSame('unsupported', $alphaVersion['status']);
525523
$this->assertSame(
526-
'This saved view uses deprecated visibility filter version 1. Consider updating it to the current version 6.',
527-
$deprecated['message'],
524+
'This saved view uses visibility filter version 1, but this Waterline build supports version 6.',
525+
$alphaVersion['message'],
528526
);
529-
530-
$deprecated2 = VisibilityFilters::versionMetadata(2);
531-
$this->assertTrue($deprecated2['supported']);
532-
$this->assertTrue($deprecated2['deprecated']);
533-
$this->assertSame('deprecated', $deprecated2['status']);
534-
535-
$notDeprecated = VisibilityFilters::versionMetadata(3);
536-
$this->assertTrue($notDeprecated['supported']);
537-
$this->assertFalse($notDeprecated['deprecated']);
538-
$this->assertSame('supported', $notDeprecated['status']);
539-
$this->assertNull($notDeprecated['message']);
540-
}
541-
542-
public function testVersionEvolutionPolicyExposesStableContract(): void
543-
{
544-
$policy = VisibilityFilters::versionEvolutionPolicy();
545-
546-
$this->assertSame(VisibilityFilters::VERSION, $policy['current_version']);
547-
$this->assertSame(VisibilityFilters::MINIMUM_SUPPORTED_VERSION, $policy['minimum_supported_version']);
548-
$this->assertSame([1, 2, 3, 4, 5, VisibilityFilters::VERSION], $policy['supported_versions']);
549-
$this->assertSame([1, 2], $policy['deprecated_versions']);
550-
$this->assertSame('system:', $policy['reserved_view_id_prefix']);
551-
$this->assertIsString($policy['upgrade_policy']);
552-
553-
foreach ($policy['deprecated_versions'] as $version) {
554-
$this->assertTrue(VisibilityFilters::isDeprecated($version));
555-
$this->assertContains($version, $policy['supported_versions']);
556-
$this->assertGreaterThanOrEqual($policy['minimum_supported_version'], $version);
557-
}
558527
}
559528

560529
public function testIsReservedViewIdGuardsSystemPrefix(): void
@@ -567,12 +536,13 @@ public function testIsReservedViewIdGuardsSystemPrefix(): void
567536
$this->assertFalse(VisibilityFilters::isReservedViewId(''));
568537
}
569538

570-
public function testDefinitionIncludesVersionEvolutionFields(): void
539+
public function testDefinitionIncludesCleanSlateVersionFields(): void
571540
{
572541
$definition = VisibilityFilters::definition();
573542

574-
$this->assertSame(VisibilityFilters::MINIMUM_SUPPORTED_VERSION, $definition['minimum_supported_version']);
575-
$this->assertSame([1, 2], $definition['deprecated_versions']);
543+
$this->assertSame([VisibilityFilters::VERSION], $definition['supported_versions']);
544+
$this->assertArrayNotHasKey('minimum_supported_version', $definition);
545+
$this->assertArrayNotHasKey('deprecated_versions', $definition);
576546
$this->assertSame('system:', $definition['reserved_view_id_prefix']);
577547
}
578548

@@ -675,31 +645,6 @@ public function testDefinitionIncludesProjectionSchemaVersion(): void
675645
$this->assertGreaterThanOrEqual(1, $definition['projection_schema_version']);
676646
}
677647

678-
public function testMixedFleetPolicyExposesStableContract(): void
679-
{
680-
$policy = VisibilityFilters::mixedFleetPolicy();
681-
682-
$this->assertSame(RunSummaryProjector::SCHEMA_VERSION, $policy['projection_schema_version']);
683-
$this->assertSame(VisibilityFilters::VERSION, $policy['filter_version']);
684-
$this->assertIsArray($policy['invariants']);
685-
$this->assertNotEmpty($policy['invariants']);
686-
687-
foreach ($policy['invariants'] as $invariant) {
688-
$this->assertIsString($invariant);
689-
$this->assertNotEmpty($invariant);
690-
}
691-
692-
$this->assertArrayHasKey('projection_backfill_authority', $policy);
693-
$backfill = $policy['projection_backfill_authority'];
694-
$this->assertArrayHasKey('trigger', $backfill);
695-
$this->assertArrayHasKey('mechanism', $backfill);
696-
$this->assertArrayHasKey('scope', $backfill);
697-
$this->assertArrayHasKey('safety', $backfill);
698-
699-
$this->assertIsString($policy['upgrade_path']);
700-
$this->assertNotEmpty($policy['upgrade_path']);
701-
}
702-
703648
public function testApplyFiltersExcludeRowsWithNullVisibilityFieldsFromFilteredViews(): void
704649
{
705650
WorkflowRunSummary::create([

0 commit comments

Comments
 (0)