diff --git a/src/features/pilots/pilot-page.test.tsx b/src/features/pilots/pilot-page.test.tsx index edd6ee2..f159c00 100644 --- a/src/features/pilots/pilot-page.test.tsx +++ b/src/features/pilots/pilot-page.test.tsx @@ -88,7 +88,9 @@ describe("PilotPage", () => { name: /close, revise, or proceed/i, }); expect(within(decisions).getByText(/^continue$/i)).toBeInTheDocument(); - expect(decisions).toHaveTextContent(/5 qualified test participants/i); + expect(decisions).toHaveTextContent( + /5 reviewers ready for an authorized test/i, + ); expect(decisions).toHaveTextContent(/3 suitable authorized projects/i); expect(within(decisions).getByText(/^revise$/i)).toBeInTheDocument(); expect(within(decisions).getByText(/^archive$/i)).toBeInTheDocument(); diff --git a/src/features/pilots/pilot-page.tsx b/src/features/pilots/pilot-page.tsx index 943b597..c7261d2 100644 --- a/src/features/pilots/pilot-page.tsx +++ b/src/features/pilots/pilot-page.tsx @@ -141,12 +141,12 @@ export function PilotPage() { { expect(within(dashboard).getByText("9")).toBeInTheDocument(); expect(within(dashboard).getByText("5")).toBeInTheDocument(); expect(within(dashboard).getByText("3")).toBeInTheDocument(); + expect(within(dashboard).getByText(/ready reviewers/i)).toBeInTheDocument(); + expect(dashboard).not.toHaveTextContent(/participant responses/i); expect(within(dashboard).getByText("2 active")).toBeInTheDocument(); expect(within(dashboard).getByText("1 accepted")).toBeInTheDocument(); expect(within(dashboard).getByText("2 spaces remain")).toBeInTheDocument(); diff --git a/src/features/pilots/pilot-readiness-panel.tsx b/src/features/pilots/pilot-readiness-panel.tsx index 818eff3..8bc9f51 100644 --- a/src/features/pilots/pilot-readiness-panel.tsx +++ b/src/features/pilots/pilot-readiness-panel.tsx @@ -18,7 +18,7 @@ const recommendationCopy: Record< continue: { label: "Continue threshold met", description: - "Participant and suitable-project evidence support preparing the published authorized test run.", + "Ready-reviewer and suitable-project evidence support preparing the published authorized test run.", }, revise: { label: "Revise before advancing", @@ -101,7 +101,7 @@ export function PilotReadinessPanel({ pilotId }: { pilotId: string }) { /> = evidence.continue_participant_threshold + and evidence.project_response_count >= evidence.continue_project_threshold + then 'continue' + when timezone('utc', now()) >= evidence.created_at + make_interval(days => evidence.evidence_window_days) + and evidence.meaningful_signal_count <= evidence.archive_signal_ceiling + then 'archive' + when timezone('utc', now()) >= evidence.created_at + make_interval(days => evidence.evidence_window_days) + then 'revise' + else 'pending' + end as recommendation + from evidence; +$$; + +comment on function public.get_pilot_readiness_summary(uuid) is + 'Returns creator/operator-only aggregate readiness: distinct current ready reviewers, explicitly scoped historical project evidence, private application totals, and a threshold preview without member identities.'; diff --git a/supabase/tests/database/idea-pilots.test.sql b/supabase/tests/database/idea-pilots.test.sql index d98ede0..4a65d64 100644 --- a/supabase/tests/database/idea-pilots.test.sql +++ b/supabase/tests/database/idea-pilots.test.sql @@ -589,6 +589,13 @@ values ('00000000-0000-4000-8000-000000000401', '00000000-0000-4000-8000-000000000411', '55555555-5555-4555-8555-555555555555'), ('00000000-0000-4000-8000-000000000401', '00000000-0000-4000-8000-000000000415', '66666666-6666-4666-8666-666666666666'); +insert into public.idea_validation_responses (question_id, option_id, profile_id) +values ( + '00000000-0000-4000-8000-000000000601', + '00000000-0000-4000-8000-000000000611', + '55555555-5555-4555-8555-555555555555' +); + set local role authenticated; set local "request.jwt.claim.sub" = '55555555-5555-4555-8555-555555555555'; set local "request.jwt.claims" = '{"sub":"55555555-5555-4555-8555-555555555555","role":"authenticated","app_metadata":{}}'; @@ -613,8 +620,8 @@ select is( )::text from public.get_pilot_readiness_summary('00000000-0000-4000-8000-000000000501') ), - row(2, 2, 1, 1, 1, 2, 'pending')::text, - 'the creator receives aggregate progress without applicant identities' + row(2, 1, 1, 1, 1, 2, 'pending')::text, + 'the creator receives current ready-reviewer and historical project aggregates without double-counting one member' ); set local "request.jwt.claim.sub" = '77777777-7777-4777-8777-777777777777'; @@ -655,6 +662,11 @@ select is( ); reset role; +insert into public.idea_validation_responses (question_id, option_id, profile_id) +values + ('00000000-0000-4000-8000-000000000601', '00000000-0000-4000-8000-000000000611', '66666666-6666-4666-8666-666666666666'), + ('00000000-0000-4000-8000-000000000601', '00000000-0000-4000-8000-000000000611', '77777777-7777-4777-8777-777777777777'); + update public.idea_pilots set continue_participant_threshold = 3, continue_project_threshold = 2 where id = '00000000-0000-4000-8000-000000000501'; diff --git a/supabase/verification/authorized-bounty-upgrade.test.sql b/supabase/verification/authorized-bounty-upgrade.test.sql index d7070e5..8038fed 100644 --- a/supabase/verification/authorized-bounty-upgrade.test.sql +++ b/supabase/verification/authorized-bounty-upgrade.test.sql @@ -59,6 +59,19 @@ update public.idea_validation_options set value = 'ready-in-range' where id = '00000000-0000-4000-8000-000000000611'; +insert into public.idea_validation_responses (question_id, option_id, profile_id) +values + ( + '00000000-0000-4000-8000-000000000401', + '00000000-0000-4000-8000-000000000411', + '00000000-0000-4000-8000-000000000101' + ), + ( + '00000000-0000-4000-8000-000000000601', + '00000000-0000-4000-8000-000000000611', + '00000000-0000-4000-8000-000000000101' + ); + create temporary table bounty_upgrade_fixture_before as select ideas.updated_at, @@ -70,6 +83,8 @@ where ideas.id = '88888888-8888-4888-8888-888888888811' \ir ../migrations/20260811193000_recast_as_authorized_bounty_network.sql \ir ../migrations/20260811193000_recast_as_authorized_bounty_network.sql +\ir ../migrations/20260813203034_fix_pilot_readiness_generation_counts.sql +\ir ../migrations/20260813203034_fix_pilot_readiness_generation_counts.sql do $$ begin @@ -152,6 +167,19 @@ begin ) <> 0 then raise exception 'unauthenticated validation summary unexpectedly returned rows'; end if; + + perform set_config( + 'request.jwt.claim.sub', + '00000000-0000-4000-8000-000000000101', + true + ); + + if ( + select row(participant_response_count, project_response_count)::text + from public.get_pilot_readiness_summary('00000000-0000-4000-8000-000000000501') + ) is distinct from row(1::bigint, 1::bigint)::text then + raise exception 'authorized bounty migration mixed historical and active pilot-readiness responses'; + end if; end $$;