diff --git a/dag/gunbc/recurring_failure_mode/a_prerendered_body_carries_no_identity_of_its_source.dag b/dag/gunbc/recurring_failure_mode/a_prerendered_body_carries_no_identity_of_its_source.dag new file mode 100644 index 00000000000..de93986d720 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/a_prerendered_body_carries_no_identity_of_its_source.dag @@ -0,0 +1,34 @@ +module gunbc.recurring_failure_mode.a_prerendered_body_carries_no_identity_of_its_source + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data a_prerendered_body_carries_no_identity_of_its_source: RecurringFailureMode = RecurringFailureMode { + identity: "a_prerendered_body_carries_no_identity_of_its_source" as NonEmptyStr, + + receipts: [ + "**a pre-rendered body carries no identity of its source** (one deployment parameterizes a fold by the authority it should answer from, and the parameter reaches every surface that renders at REQUEST time -- but a surface rendered EARLIER, by a different process, and merely read back at request time, answers from whatever authority THAT process was given. The request-time parameter is real and the read-back is real; what does not exist is any record, on the bytes, of which authority produced them. ", + + "INVALID STATE: two processes of one deployment serving a response set derived from two different authorities, with no typed refusal and no observable at either end that distinguishes it from the coherent case. ", + + "WHY IT SURVIVES REVIEW, and why it is worth a row rather than a note: the parameterization is genuinely complete on both entries. Each half is individually correct, each is individually witnessed, and the seam is not inside any fold a reviewer reads -- it is between two processes that never exchange the parameter. A reviewer checking that the plan reaches every consumer finds that it does. A reviewer checking that the read-back is faithful finds that it is. The defect is that FAITHFUL TO WHAT is unanswerable from the artifact. ", + + "SPECIMEN (PR #10987). gunbc.roadmap_serve roadmap_serve_handle_over takes the roadmap plan as a parameter and every request-time surface reads it. The daily workspace page at path / does not render at request time: gunbc.roadmap_served_observation writes it at the belt tick through served_observation_observe_and_write_over, and the route serves the stored body. Supply a plan at the serve entry alone and / answers from the tick's plan, 200, no refusal. The two entries are both parameterized -- that is what makes this a seam rather than a missing parameter. ", + + "DISTINGUISHING FACTS, so the row discriminates rather than warning generally. It requires all three: a value parameterized at an entry; a consumer materialized by a DIFFERENT entry ahead of time; and a stored artifact whose schema omits the parameter it was derived under. Remove the third and the mismatch is detectable. A cache keyed by its inputs is NOT this class -- the key is exactly the identity this class lacks. A surface that recomputes per request is not this class either, because there is one process and one parameter. ", + + "NOT THE ABSORBING FALLBACK, and not a stale cache: nothing degrades and nothing widens. The stored body is a correct, current render of a coherent authority. What is false is only the implied claim that it is the authority THIS reader's entry was given, and that claim is made by juxtaposition rather than by any statement a fold could refuse. ", + + "RUNG: FOUND below the ladder -- a reader served a page derived from an authority they did not select, with no typed diagnostic anywhere -- and DESIGN 4b does not admit that as a low rung: silent wrongness is outside the ladder and forbidden outright. The specimen diff was the thing that created the constructor, so it could not file the row and ship the state. ", + + "RUNG NOW 1, mitigatable, and the split matters. The agreement is a DECLARED fact of the call (gunbc.roadmap_serve ServedDailyBodyAuthority): a caller that cannot state it gets a located refusal on that one route instead of a 200 from an unknown authority, so the UNDECLARED case is no longer silent and no longer reachable -- the coproduct has no third variant that serves. What remains is the DECLARED-BUT-FALSE case, where a caller asserts agreement its own tick does not honour. That is contained rather than prevented, because nothing on the serving side can check the assertion, and it is the residual the ceiling below is about. Stating rung 1 for the whole class rather than 3 for its refusing half is the 4b(1) rule that a class sits at the MINIMUM across its paths. ", + + "CEILING 3, structurally guaranteed, and NOT 4. The mismatch is a relation between two independently launched processes, so it cannot be made unconstructible -- nothing stops an operator from starting a tick on one authority and a server on another. What CAN be derived is the refusal: if the stored artifact carries the identity of the authority it was rendered under, the read-back compares it to the identity the serving entry was given and refuses with a located cause instead of answering 200. That replaces a TRUSTED declaration with a CHECKED one, which is the whole distance between rung 1 and the ceiling. ", + + "NEXT-RUNG TRIGGER, a capability rather than an artifact: a materialized-surface identity that binds a stored body to the authority it was derived under, sufficient for a read-back to decide agreement with the authority its own entry holds and to refuse on disagreement. Stamping a field into one snapshot type is not the trigger unless the read-back is obligated to consult it -- an identity nothing compares is the decoration DESIGN 4b names, and would leave the class exactly where it is while appearing to retire it. ", + + "REVIEW TELL: a diff that parameterizes an authority and then explains, in prose, that one surface is served from a body rendered elsewhere. Ask what the stored bytes say about which authority produced them. If the answer is nothing, the seam is undetectable, and the two wrong answers are to document it or to file it at a low rung -- both leave the forbidden state reachable. The available arm is refusal at a declared boundary, today, and the row is what carries the debt from there to the checked version.", + ], + + evidence: [], +} diff --git a/dag/gunbc/roadmap/roadmap_belt_actuate.dag b/dag/gunbc/roadmap/roadmap_belt_actuate.dag index 742c44a035d..96d88ed6d75 100644 --- a/dag/gunbc/roadmap/roadmap_belt_actuate.dag +++ b/dag/gunbc/roadmap/roadmap_belt_actuate.dag @@ -26,7 +26,7 @@ import gunbc.roadmap_dispatch_actuator { } import extdeps.git { shape_git_merge_base_args } import gunbc.roadmap_authority { - roadmap_authority_projection, + RoadmapAuthorityProjection, roadmap_authority_projection, RoadmapAuthorityProjected, RoadmapAuthorityProjectionRefused, authored_merged_prs, } @@ -6054,9 +6054,16 @@ fn belt_page_sessions_need(standing: LaunchHostStanding, graph: LaunchGraphStand }) } -fn belt_launch_host_standing_for_page(instance: HostDashboardInstance) -> LaunchHostStanding { +// The page's standing is decided against the plan the page is about to RENDER. Passing the plan in +// rather than reading the public carrier here is what keeps the two halves of one response honest: +// a caller rendering a different plan would otherwise get session-need decided from a roadmap its +// reader never sees. +fn belt_launch_host_standing_for_page_over( + instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, +) -> LaunchHostStanding { let pre = belt_launch_host_standing(instance: instance) - match roadmap_authority_projection() { + match plan { RoadmapAuthorityProjectionRefused { detail: _ } => pre RoadmapAuthorityProjected { doc, accepted: _ } => { let graph = launch_graph_of_document(doc: doc) @@ -6092,6 +6099,23 @@ fn belt_dispatch_node_for_instance( belt_dispatch_node_staged(instance: instance, standing: belt_launch_host_standing(instance: instance), node_id: node_id) } +// The dispatch route reaches the SAME staged fold with a caller-supplied plan. belt_dispatch_node_staged_over +// already took the graph as a parameter, so this adds no second decision path -- it only supplies +// launch_graph_of_projection over the given plan instead of over the public one. +fn belt_dispatch_node_for_instance_over( + instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, + node_id: String, +) -> BeltSpawnOutcome { + belt_dispatch_node_staged_over( + instance: instance, + standing: belt_launch_host_standing(instance: instance), + graph: launch_graph_of_projection(proj: plan), + merged: authored_merged_prs(), + node_id: node_id, + ) +} + // THE ROUTE'S DECISION PATH after the staged host observation, and the seam the hermetic // real-driver controls exercise: given a pre-session standing (sessions pending), the node's // model-only gates are decided first; only LaunchStageNeedsSessions lists tmux, so an unknown, diff --git a/dag/gunbc/roadmap/roadmap_forecast.dag b/dag/gunbc/roadmap/roadmap_forecast.dag index 201ae194595..da0bbdcc2f1 100644 --- a/dag/gunbc/roadmap/roadmap_forecast.dag +++ b/dag/gunbc/roadmap/roadmap_forecast.dag @@ -43,10 +43,8 @@ import gunbc.roadmap_authority { declared_roadmap_nodes, active_roadmap_nodes_for_accepted, active_roadmap_edges_for_accepted, - roadmap_authority_projection, + RoadmapAuthorityProjection, roadmap_authority_projection, RoadmapAuthorityProjected, RoadmapAuthorityProjectionRefused, - accepted_roadmap_node_ids_projection, - AcceptedRoadmapNodeIdsProjected, AcceptedRoadmapNodeIdsProjectionRefused, roadmap_acceptance_receipts, RoadmapAcceptanceReceiptsProjected, RoadmapAcceptanceReceiptsProjectionRefused, @@ -861,28 +859,40 @@ fn schedule_forecast( } } } -fn live_roadmap_schedule_forecast( +// THE FORECAST'S PLAN IS A PARAMETER. The accepted set is carried BY the projection -- it is the +// field roadmap_authority_projection fills from accepted_roadmap_node_ids_projection -- so the fold +// reads it from the plan it was handed rather than re-deriving it from the public carrier. That is +// what makes a caller-supplied plan forecastable at all: a second read would have answered about +// the public roadmap while the nodes came from the caller's. +fn roadmap_schedule_forecast_over( + plan: RoadmapAuthorityProjection, assumptions: ScheduleForecastAssumptions, anchor: ForecastAnchorObservation, ) -> ScheduleForecastResult { - match roadmap_authority_projection() { + match plan { RoadmapAuthorityProjectionRefused { detail: detail } => ScheduleForecastRefused { refusals: [ForecastRoadmapAuthorityRefused { detail: detail }] } - RoadmapAuthorityProjected { doc: _, accepted: _ } => - match accepted_roadmap_node_ids_projection() { - AcceptedRoadmapNodeIdsProjected { ids: accepted } => - let builds = roadmap_cycle_time_observation_builds() - schedule_forecast( - nodes: active_roadmap_nodes_for_accepted(accepted: accepted), - edges: active_roadmap_edges_for_accepted(accepted: accepted), - observations: accepted_cycle_time_observations(builds: builds), - history_refusals: cycle_time_history_refusals(builds: builds), - population_exclusions: cycle_time_population_exclusions(builds: builds), - assumptions: assumptions, - anchor: anchor, - ) - AcceptedRoadmapNodeIdsProjectionRefused { detail: detail } => - ScheduleForecastRefused { refusals: [ForecastRoadmapAuthorityRefused { detail: detail }] } - } + RoadmapAuthorityProjected { doc: _, accepted: accepted } => + let builds = roadmap_cycle_time_observation_builds() + schedule_forecast( + nodes: active_roadmap_nodes_for_accepted(accepted: accepted), + edges: active_roadmap_edges_for_accepted(accepted: accepted), + observations: accepted_cycle_time_observations(builds: builds), + history_refusals: cycle_time_history_refusals(builds: builds), + population_exclusions: cycle_time_population_exclusions(builds: builds), + assumptions: assumptions, + anchor: anchor, + ) } } + +fn live_roadmap_schedule_forecast( + assumptions: ScheduleForecastAssumptions, + anchor: ForecastAnchorObservation, +) -> ScheduleForecastResult { + roadmap_schedule_forecast_over( + plan: roadmap_authority_projection(), + assumptions: assumptions, + anchor: anchor, + ) +} diff --git a/dag/gunbc/roadmap/roadmap_page.dag b/dag/gunbc/roadmap/roadmap_page.dag index 2d5a1717092..83d8801d057 100644 --- a/dag/gunbc/roadmap/roadmap_page.dag +++ b/dag/gunbc/roadmap/roadmap_page.dag @@ -971,20 +971,6 @@ fn v1_exit_program_progress_view_for_accepted(accepted_ids: List, } } -fn v1_exit_program_progress_view(ready_count: Int) -> ProgramProgressView { - match accepted_roadmap_node_ids_projection() { - AcceptedRoadmapNodeIdsProjectionRefused { detail: _ } => - ProgramProgressView { - name: "v1 exit (acceptance carrier refused)", - completed: 0, - total: 0, - ready_obligation_count: ready_count, - } - AcceptedRoadmapNodeIdsProjected { ids: accepted_ids } => - v1_exit_program_progress_view_for_accepted(accepted_ids: accepted_ids, ready_count: ready_count) - } -} - fn program_progress_markup_of(v: ProgramProgressView) -> Fragment { el_class("section", "program-progress", [ el_class("span", "program-progress-name", [ txt(v.name) ]), @@ -1090,29 +1076,6 @@ fn daily_workspace_view_of_for_accepted( members: live_work_family_members_for_accepted(accepted: accepted_ids)) } -fn daily_workspace_view_of(doc: RoadmapDocument, merged: List, attempts: List, attempts_refused: String?, standings: RoadmapStandings, launch: LaunchHostStanding) -> DailyWorkspaceView { - match accepted_roadmap_node_ids_projection() { - AcceptedRoadmapNodeIdsProjectionRefused { detail: _ } => - daily_workspace_view_of_for_accepted( - doc: doc, - merged: merged, - accepted_ids: [], - attempts: attempts, - attempts_refused: attempts_refused, standings: standings, - launch: launch, - ) - AcceptedRoadmapNodeIdsProjected { ids: accepted_ids } => - daily_workspace_view_of_for_accepted( - doc: doc, - merged: merged, - accepted_ids: accepted_ids, - attempts: attempts, - attempts_refused: attempts_refused, standings: standings, - launch: launch, - ) - } -} - fn roadmap_daily_workspace_page_impl_for_accepted( doc: RoadmapDocument, merged: List, @@ -1190,34 +1153,6 @@ fn roadmap_fleet_page() -> Fragment { } } -fn roadmap_daily_workspace_page_impl(doc: RoadmapDocument, merged: List, main_prefix: List, attempts: List, attempts_refused: String?, - standings: RoadmapStandings, launch: LaunchHostStanding) -> Fragment { - match accepted_roadmap_node_ids_projection() { - AcceptedRoadmapNodeIdsProjectionRefused { detail: _ } => - roadmap_daily_workspace_page_impl_for_accepted( - doc: doc, - merged: merged, - accepted_ids: [], - main_prefix: main_prefix, - attempts: attempts, - attempts_refused: attempts_refused, - standings: standings, - launch: launch, - ) - AcceptedRoadmapNodeIdsProjected { ids: accepted_ids } => - roadmap_daily_workspace_page_impl_for_accepted( - doc: doc, - merged: merged, - accepted_ids: accepted_ids, - main_prefix: main_prefix, - attempts: attempts, - attempts_refused: attempts_refused, - standings: standings, - launch: launch, - ) - } -} - fn roadmap_page_impl(doc: RoadmapDocument, merged: List, main_prefix: List, launch: LaunchHostStanding) -> Fragment { let ctx = page_launch_context(doc: doc, merged: merged, launch: launch) let lead = map(doc.lead_lanes, s => section_markup(s: s, merged: merged, launch: ctx)) @@ -1294,10 +1229,6 @@ fn roadmap_page_for_authority() -> Fragment { roadmap_page_for_projection(proj: roadmap_authority_projection()) } -fn roadmap_page_for_authority_launch(launch: LaunchHostStanding) -> Fragment { - roadmap_page_for_projection_launch(proj: roadmap_authority_projection(), launch: launch) -} - fn roadmap_page_for_projection(proj: RoadmapAuthorityProjection) -> Fragment { roadmap_page_for_projection_launch(proj: proj, launch: launch_host_unobserved_static_render()) } @@ -1327,26 +1258,30 @@ fn roadmap_page_for_projection_launch(proj: RoadmapAuthorityProjection, launch: } } +// THE ACCEPTED SET IS SUPPLIED HERE TOO, AND THAT IS WHY THE LEAK HAS NO CONSTRUCTOR LEFT. +// +// These two entries used to reach roadmap_daily_workspace_page_impl, which read +// accepted_roadmap_node_ids_projection() itself. That fold was also the refusal arm of +// roadmap_daily_workspace_page_for_projection_observed, so a caller-supplied plan that failed to +// project rendered beside the PUBLIC accepted set (review 63317). Routing that one arm to the +// _for_accepted form closed the route, but left the ambient-reading fold standing -- and a probe +// cannot guard it: under the hermetic witness route the carrier read REFUSES and yields the same +// empty set, so the defect is invisible to any witness that could be enrolled (measured: the +// leak restored in an isolated worktree, the probe still PASSED). DESIGN 4b says a check whose RED +// is not authorable is not a weak wall but a decoration, and 5 says prefer construction over +// validation. So the fold is deleted rather than watched: nothing below the parameterized route +// can name the public accepted set any more, and these two get the empty one, which is what their +// own "the event carrier is not consulted" already claimed and did not deliver. + fn roadmap_daily_workspace_page(doc: RoadmapDocument, merged: List) -> Fragment { - roadmap_daily_workspace_page_impl(doc: doc, merged: merged, main_prefix: [], attempts: [], attempts_refused: none, standings: StandingsUnobserved { reason: "static render: the event carrier is not consulted" }, launch: launch_host_unobserved_static_render()) + roadmap_daily_workspace_page_impl_for_accepted(doc: doc, merged: merged, accepted_ids: [], main_prefix: [], attempts: [], attempts_refused: none, standings: StandingsUnobserved { reason: "static render: the event carrier is not consulted" }, launch: launch_host_unobserved_static_render()) } fn roadmap_daily_workspace_page_launch(doc: RoadmapDocument, merged: List, launch: LaunchHostStanding) -> Fragment { - roadmap_daily_workspace_page_impl(doc: doc, merged: merged, main_prefix: [], attempts: [], attempts_refused: none, standings: StandingsUnobserved { reason: "static render: the event carrier is not consulted" }, launch: launch) -} - -// The served daily workspace consumes the OBSERVED attempt evidence at render (the serve handler decomposes the belt observation and passes progress rows or the located refusal), so the active band and every server-rendered activity region are real facts, not placeholders — the same decided views the /workflow.json wire carries, giving the client poll an identical starting DOM (the parity obligation's server half). The zero-argument form stays pure (empty attempts, nominal observation) for witnesses that assert composition without observation. -fn roadmap_daily_workspace_page_for_authority_observed(attempts: List, attempts_refused: String?, - standings: RoadmapStandings, launch: LaunchHostStanding) -> Fragment { - roadmap_daily_workspace_page_for_projection_observed( - proj: roadmap_authority_projection(), - attempts: attempts, - attempts_refused: attempts_refused, - standings: standings, - launch: launch, - ) + roadmap_daily_workspace_page_impl_for_accepted(doc: doc, merged: merged, accepted_ids: [], main_prefix: [], attempts: [], attempts_refused: none, standings: StandingsUnobserved { reason: "static render: the event carrier is not consulted" }, launch: launch) } +// The served daily workspace consumes the OBSERVED attempt evidence at render (the tick decomposes the belt observation and passes progress rows or the located refusal), so the active band and every server-rendered activity region are real facts, not placeholders — the same decided views the /workflow.json wire carries, giving the client poll an identical starting DOM (the parity obligation's server half). The plan is a parameter because the caller that renders it is the caller that chose it. fn roadmap_daily_workspace_page_for_projection_observed( proj: RoadmapAuthorityProjection, attempts: List, @@ -1356,9 +1291,10 @@ fn roadmap_daily_workspace_page_for_projection_observed( ) -> Fragment { match proj { RoadmapAuthorityProjectionRefused { detail: detail } => - roadmap_daily_workspace_page_impl( + roadmap_daily_workspace_page_impl_for_accepted( doc: RoadmapDocument { preamble: [], lead_lanes: [], sections: [] }, merged: [], + accepted_ids: [], main_prefix: [ dashboard_instance_banner(), roadmap_authority_refusal_markup(detail: detail), diff --git a/dag/gunbc/roadmap/roadmap_serve.dag b/dag/gunbc/roadmap/roadmap_serve.dag index 04bad61bb21..b1400395c35 100644 --- a/dag/gunbc/roadmap/roadmap_serve.dag +++ b/dag/gunbc/roadmap/roadmap_serve.dag @@ -41,7 +41,8 @@ import gunbc.roadmap_launch_admission { LaunchAlreadyLive, LaunchStaleSession, LaunchLivenessUnobserved, LaunchSessionMultiplicityConflict, LaunchNoCapacity, LaunchCauseNotPermitted, LaunchGateNotEvaluated, } -import gunbc.roadmap_page { roadmap_page_for_authority_launch, roadmap_daily_workspace_page_for_authority_observed, roadmap_fleet_page } +import gunbc.roadmap_page { roadmap_page_for_projection_launch, roadmap_fleet_page } +import gunbc.roadmap_authority { RoadmapAuthorityProjection, roadmap_authority_projection } import gunbc.roadmap_component { dispatch_client_js_source, roadmap_dispatch_asset_path, sandbox_client_js_source, sandbox_asset_path, @@ -56,11 +57,18 @@ import gunbc.roadmap_instrument_tuner { instrument_tuner_page } import gunbc.roadmap_instrument_motion { instrument_motion_page } import gunbc.roadmap_repo_atlas_sandbox { repo_atlas_page } import gunbc.roadmap_static_site { - roadmap_site_roadmap_md_body, - roadmap_site_dispatch_json_body, + roadmap_site_roadmap_md_body_over, + roadmap_site_dispatch_json_body_over, roadmap_site_healthz_body_for_release, } -import gunbc.roadmap_site_surface_render { page_render_refusal_body } +import gunbc.roadmap_site_surface_render { + page_render_refusal_body, + roadmap_site_health_path, + roadmap_site_roadmap_url_path, + roadmap_site_dispatch_url_path, + roadmap_site_daily_url_path, + roadmap_site_full_url_path, +} import gunbc.roadmap_served_observation { DailyPage, AttemptsJson, WorkflowJson, SessionsJson, served_observation_surface_response_for_instance, @@ -68,8 +76,8 @@ import gunbc.roadmap_served_observation { } import gunbc.roadmap_belt_actuate { BeltSpawnOutcome, Spawned, SpawnFailed, SpawnNotAdmitted, - belt_spawn_outcome_json, belt_launch_host_standing_for_page, - belt_dispatch_node, belt_dispatch_node_for_instance, + belt_spawn_outcome_json, belt_launch_host_standing_for_page_over, + belt_dispatch_node, belt_dispatch_node_for_instance_over, belt_dispatch_result_for_label, belt_dispatch_all_status_labels, BeltStopResult, belt_stop_node, belt_stop_node_for_instance, @@ -223,14 +231,43 @@ type RoadmapServeTableBuild // what is being decided and nothing else; the button on that page POSTs to the same path, and // that request is the only one that commits. Same capability in both, different consequence, and // the split is what keeps "opened the link" distinguishable from "decided". +// THE SERVED PATH IS ONE FACT. gunbc.roadmap_site_surface_render already declared each of these +// paths as data -- the static site, the surface-observation bundle and the deploy witnesses all +// cite those constants -- while these rows carried a second spelling of the same string. Two copies +// of a path agree until one moves, and the one that moves silently is the one nothing reads back: +// a witness spelling "/roadmap.md" reaches a 404 and asserts nothing (review 63317, and the +// operator's live check against the running instance). The rows now consume the declaration, so a +// renamed route moves the routing table, the static artifact and every witness together. +// THE ONE FACT THE SERVING PROCESS CANNOT OBSERVE, DECLARED SO IT CAN REFUSE. +// +// Route / is served from a body the BELT TICK rendered, under whatever plan that process held. The +// stored body carries no identity of the authority it came from, so a serving process handed a +// plan cannot check whether the body agrees with it -- the class is filed as +// gunbc.recurring_failure_mode.a_prerendered_body_carries_no_identity_of_its_source. +// +// That made this entry's plan parameter a constructor for silent wrongness: before the parameter +// existed no caller COULD diverge, and DESIGN 4b puts silent wrongness outside the ladder and +// forbids it outright rather than admitting it at a low rung. A note saying so is not a refusal +// (4c), so the honest arm available today is the one 5 names: refuse, never widen. +// +// The agreement is therefore a DECLARED fact of the call rather than something inferred. A caller +// whose own tick renders the daily body under the same plan says so and is served; a caller that +// cannot say so gets a located refusal on that ONE route, and every other route still answers from +// its plan. This is 4b's "outside the modeled guarantee" column handled at a declared boundary -- +// observed, refused, or mitigated, never fabricated -- not a fifth rung and not a proof. + +type ServedDailyBodyAuthority + = DailyBodyRenderedUnderThisPlan + | DailyBodyAuthorityUnknown + fn roadmap_serve_route_specs() -> List { [ - RoadmapServeRouteSpec { method: GET, raw: "/", handler: RoadmapDailyPageHandler }, - RoadmapServeRouteSpec { method: GET, raw: "/roadmap", handler: RoadmapFullPageHandler }, + RoadmapServeRouteSpec { method: GET, raw: roadmap_site_daily_url_path as String, handler: RoadmapDailyPageHandler }, + RoadmapServeRouteSpec { method: GET, raw: roadmap_site_full_url_path as String, handler: RoadmapFullPageHandler }, RoadmapServeRouteSpec { method: GET, raw: "/fleet", handler: FleetStandingPageHandler }, - RoadmapServeRouteSpec { method: GET, raw: "/ROADMAP.md", handler: RoadmapMdHandler }, - RoadmapServeRouteSpec { method: GET, raw: "/target/roadmap-dispatch.json", handler: DispatchJsonHandler }, - RoadmapServeRouteSpec { method: GET, raw: "/healthz", handler: HealthzHandler }, + RoadmapServeRouteSpec { method: GET, raw: roadmap_site_roadmap_url_path as String, handler: RoadmapMdHandler }, + RoadmapServeRouteSpec { method: GET, raw: roadmap_site_dispatch_url_path as String, handler: DispatchJsonHandler }, + RoadmapServeRouteSpec { method: GET, raw: roadmap_site_health_path as String, handler: HealthzHandler }, RoadmapServeRouteSpec { method: GET, raw: "/instance.json", handler: DashboardInstanceHandler }, RoadmapServeRouteSpec { method: GET, raw: "/provider.json", handler: ProviderReadinessHandler }, RoadmapServeRouteSpec { method: GET, raw: "/sessions.json", handler: SessionsJsonHandler }, @@ -403,8 +440,9 @@ fn belt_dispatch_response(r: BeltSpawnOutcome) -> ServeHttpResponse { // backstop for that unreachable arm — a 400 refusal, never a dispatch with a fabricated id (DESIGN // 5: an unreachable arm refuses, never fabricates). -fn serve_dispatch_handler_response_for_instance( +fn serve_dispatch_handler_response_over( instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, params: List, ) -> ServeHttpResponse { let node_id = path_param_value(params: params, name: "node_id") @@ -416,11 +454,22 @@ fn serve_dispatch_handler_response_for_instance( ) } else { belt_dispatch_response( - r: belt_dispatch_node_for_instance(instance: instance, node_id: node_id), + r: belt_dispatch_node_for_instance_over(instance: instance, plan: plan, node_id: node_id), ) } } +fn serve_dispatch_handler_response_for_instance( + instance: HostDashboardInstance, + params: List, +) -> ServeHttpResponse { + serve_dispatch_handler_response_over( + instance: instance, + plan: roadmap_authority_projection(), + params: params, + ) +} + // POST /publish/NODE_ID is the publication producer's live trigger, and it exists because belt_tick // has none. Publication is wired into that actuation pass beside verification and nothing drives // it, so without this route the receipt would never be written in production and the row's lamp @@ -587,19 +636,62 @@ fn sandbox_echo_response(request: ServeHttpRequest) -> ServeHttpResponse { // formerly accepted at the seam and dropped before invoke, so a body-reading POST handler would // have silently seen the empty string — a latent widen). -fn roadmap_serve_invoke_for_instance( +// THE PLAN TRAVELS WITH THE REQUEST, exactly as the instance already does. Which plan a process +// serves is fixed by its serve entry function -- `gunbc serve` binds --entry/--function and carries +// no per-request argument -- so an entry declared elsewhere supplies its own projected plan by +// CALLING this fold, and nothing here enumerates or registers callers. The handlers that consult a +// roadmap read the parameter instead of the public carrier, so one response cannot mix two plans. +// +// WHICH HANDLERS IGNORE IT, AND THE ONE THAT ONLY LOOKS LIKE IT DOES. Assets, the sandbox echo and +// the approval routes consult no roadmap at all. The sessions, attempts, workflow and observation +// surfaces read bodies the belt tick already wrote, and none of them is a roadmap render. +// +// RoadmapDailyPageHandler IS a roadmap render and must not be filed with them (review 63341, which +// caught this note grouping it there). Its plan is bound EARLIER, at the tick that rendered the +// body, by gunbc.roadmap_served_observation served_observation_observe_and_write_over -- so the +// daily page is parameterized, on the other entry. The consequence a caller has to know: supplying +// a plan HERE does not reach `/`. A process serving its own plan must supply it at BOTH entries, +// the serve entry and the tick entry; supply it at only this one and `/` answers from whatever plan +// the tick that wrote the body was given, with no refusal, because a pre-rendered body carries no +// record of the plan it came from. That is a real seam between two processes, not a gap inside this +// fold, and it is stated rather than papered over: nothing here can detect the mismatch. +fn roadmap_serve_invoke_over( instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, + daily_body: ServedDailyBodyAuthority, handler: RoadmapServeHandler, params: List, request: ServeHttpRequest, release_revision: CommitSha, ) -> ServeHttpResponse { match handler { - RoadmapDailyPageHandler => serve_daily_page_response_for_instance(instance: instance) - RoadmapFullPageHandler => serve_page_response(page: roadmap_page_for_authority_launch(launch: belt_launch_host_standing_for_page(instance: instance))) + RoadmapDailyPageHandler => + match daily_body { + DailyBodyRenderedUnderThisPlan => serve_daily_page_response_for_instance(instance: instance) + DailyBodyAuthorityUnknown => + serve_text_response( + status: 503, + content_type: text_plain_utf8, + body: join([ + "the daily workspace is served from a body this process did not render: the belt tick ", + "wrote it under the plan THAT process held, and a stored body carries no identity of ", + "the authority it came from, so agreement with the plan this entry was given cannot ", + "be decided here. Refusing rather than answering from an unknown authority ", + "(gunbc.recurring_failure_mode.a_prerendered_body_carries_no_identity_of_its_source). ", + "Bind the same plan at the tick entry, gunbc.roadmap_served_observation ", + "served_observation_observe_and_write_over, and declare it with ", + "DailyBodyRenderedUnderThisPlan.\n", + ], ""), + ) + } + RoadmapFullPageHandler => + serve_page_response(page: roadmap_page_for_projection_launch( + proj: plan, + launch: belt_launch_host_standing_for_page_over(instance: instance, plan: plan), + )) FleetStandingPageHandler => serve_page_response(page: roadmap_fleet_page()) - RoadmapMdHandler => serve_text_response(status: 200, content_type: text_plain_utf8, body: roadmap_site_roadmap_md_body()) - DispatchJsonHandler => serve_text_response(status: 200, content_type: application_json_utf8, body: roadmap_site_dispatch_json_body()) + RoadmapMdHandler => serve_text_response(status: 200, content_type: text_plain_utf8, body: roadmap_site_roadmap_md_body_over(plan: plan)) + DispatchJsonHandler => serve_text_response(status: 200, content_type: application_json_utf8, body: roadmap_site_dispatch_json_body_over(plan: plan)) HealthzHandler => serve_text_response(status: 200, content_type: application_json_utf8, body: roadmap_site_healthz_body_for_release(release_revision: release_revision)) DashboardInstanceHandler => serve_text_response( @@ -614,7 +706,7 @@ fn roadmap_serve_invoke_for_instance( body: dashboard_provider_readiness_json(instance: instance), ) BeltDispatchHandler => - serve_dispatch_handler_response_for_instance(instance: instance, params: params) + serve_dispatch_handler_response_over(instance: instance, plan: plan, params: params) DispatchAssetHandler => serve_text_response(status: 200, content_type: text_javascript_utf8, body: dispatch_client_js_source()) SandboxPageHandler => serve_page_response(page: sandbox_page()) InstrumentSandboxPageHandler => serve_page_response(page: instrument_sandbox_page()) @@ -636,6 +728,24 @@ fn roadmap_serve_invoke_for_instance( } } +fn roadmap_serve_invoke_for_instance( + instance: HostDashboardInstance, + handler: RoadmapServeHandler, + params: List, + request: ServeHttpRequest, + release_revision: CommitSha, +) -> ServeHttpResponse { + roadmap_serve_invoke_over( + instance: instance, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + handler: handler, + params: params, + request: request, + release_revision: release_revision, + ) +} + fn roadmap_serve_invoke( handler: RoadmapServeHandler, params: List, @@ -786,16 +896,20 @@ fn http_method_label_join(methods: List) -> String { }), ", ") } -fn roadmap_serve_selection_response_for_instance( +fn roadmap_serve_selection_response_over( instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, + daily_body: ServedDailyBodyAuthority, sel: RouteSelection, request: ServeHttpRequest, release_revision: CommitSha, ) -> ServeHttpResponse { match sel { SelectedDynamic { handler: h, params: ps } => - roadmap_serve_invoke_for_instance( + roadmap_serve_invoke_over( instance: instance, + plan: plan, + daily_body: daily_body, handler: h, params: ps, request: request, @@ -814,6 +928,22 @@ fn roadmap_serve_selection_response_for_instance( } } +fn roadmap_serve_selection_response_for_instance( + instance: HostDashboardInstance, + sel: RouteSelection, + request: ServeHttpRequest, + release_revision: CommitSha, +) -> ServeHttpResponse { + roadmap_serve_selection_response_over( + instance: instance, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + sel: sel, + request: request, + release_revision: release_revision, + ) +} + fn roadmap_serve_selection_response( sel: RouteSelection, request: ServeHttpRequest, @@ -827,8 +957,10 @@ fn roadmap_serve_selection_response( ) } -fn roadmap_serve_respond_for_instance( +fn roadmap_serve_respond_over( instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, + daily_body: ServedDailyBodyAuthority, method_label: String, path: String, body: String, @@ -856,8 +988,10 @@ fn roadmap_serve_respond_for_instance( ], ""), ) RoadmapServeTable { table: t } => - roadmap_serve_selection_response_for_instance( + roadmap_serve_selection_response_over( instance: instance, + plan: plan, + daily_body: daily_body, sel: serve_select_route(table: t, method: m, path: path), request: ServeHttpRequest { method: m, @@ -871,6 +1005,26 @@ fn roadmap_serve_respond_for_instance( } } +fn roadmap_serve_respond_for_instance( + instance: HostDashboardInstance, + method_label: String, + path: String, + body: String, + tailscale_identity: String, + release_revision: CommitSha, +) -> ServeHttpResponse { + roadmap_serve_respond_over( + instance: instance, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method_label: method_label, + path: path, + body: body, + tailscale_identity: tailscale_identity, + release_revision: release_revision, + ) +} + fn roadmap_serve_respond( method_label: String, path: String, @@ -899,15 +1053,37 @@ fn roadmap_serve_respond( // It is threaded through the entry rather than read at the handler because there is exactly one // entry, and a fact every route may need to consult belongs on the request that reaches them all. // Handlers that do not need it ignore it; the approval routes refuse without it. -fn roadmap_serve_handle( +// +// THE PLAN AUTHORITY IS THE PARAMETER, AND A SERVE ENTRY IS THE WHOLE INTEGRATION. +// +// Instance selection is already by serve entry function, because `gunbc serve` binds --entry and +// --function once for the process's life and carries no per-request argument. The plan a process +// serves is the same KIND of fact -- fixed at launch, constant for every request -- so it arrives +// the same way: an entry function declared in whatever module owns that plan calls this fold with +// its own projection. +// +// What is passed is the PROJECTED PLAN, not a path or a source root. A plan that failed to project +// arrives as RoadmapAuthorityProjectionRefused and every consumer below refuses in its own +// vocabulary; handing over a location instead would have made an unreadable plan indistinguishable +// from an empty one at the surfaces that render it. +// +// It is deliberately NOT a registry. Nothing here enumerates plans, and no table is filled in from +// elsewhere: the direction of the dependency is that the caller reaches this fold, so this module +// stays unaware of who calls it and needs no edit when another one does. +fn roadmap_serve_handle_over( + instance: HostDashboardInstance, + plan: RoadmapAuthorityProjection, + daily_body: ServedDailyBodyAuthority, method: String, path: String, body: String, tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( - instance: srv1_live_dashboard_instance(), + serve_wire_response(r: roadmap_serve_respond_over( + instance: instance, + plan: plan, + daily_body: daily_body, method_label: method, path: path, body: body, @@ -916,6 +1092,25 @@ fn roadmap_serve_handle( )) } +fn roadmap_serve_handle( + method: String, + path: String, + body: String, + tailscale_identity: String, + release_revision: CommitSha, +) -> ServeWireResponse { + roadmap_serve_handle_over( + instance: srv1_live_dashboard_instance(), + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, + path: path, + body: body, + tailscale_identity: tailscale_identity, + release_revision: release_revision, + ) +} + // THE OPERATOR MACBOOK'S ENTRY. Instance selection is by serve entry function -- the shape // gunbc.roadmap_dashboard_instance declares and srv1_lab already follows -- so serving the // workspace from the development checkout is one row here rather than a resolver that reads the @@ -930,14 +1125,16 @@ fn roadmap_serve_handle_macbook_local( tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( + roadmap_serve_handle_over( instance: macbook_local_dashboard_instance(), - method_label: method, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, path: path, body: body, tailscale_identity: tailscale_identity, release_revision: release_revision, - )) + ) } fn roadmap_serve_handle_srv1_lab( @@ -947,14 +1144,16 @@ fn roadmap_serve_handle_srv1_lab( tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( + roadmap_serve_handle_over( instance: srv1_lab_dashboard_instance(), - method_label: method, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, path: path, body: body, tailscale_identity: tailscale_identity, release_revision: release_revision, - )) + ) } fn roadmap_serve_handle_srv2_preview( @@ -964,14 +1163,16 @@ fn roadmap_serve_handle_srv2_preview( tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( + roadmap_serve_handle_over( instance: srv2_preview_dashboard_instance(), - method_label: method, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, path: path, body: body, tailscale_identity: tailscale_identity, release_revision: release_revision, - )) + ) } // THE srv2 DEPLOYMENT'S ENTRY. Same selection-by-entry-function shape the rest of this family @@ -984,14 +1185,16 @@ fn roadmap_serve_handle_srv2_deploy( tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( + roadmap_serve_handle_over( instance: srv2_deploy_dashboard_instance(), - method_label: method, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, path: path, body: body, tailscale_identity: tailscale_identity, release_revision: release_revision, - )) + ) } fn roadmap_serve_handle_srv2_lab( @@ -1001,12 +1204,14 @@ fn roadmap_serve_handle_srv2_lab( tailscale_identity: String, release_revision: CommitSha, ) -> ServeWireResponse { - serve_wire_response(r: roadmap_serve_respond_for_instance( + roadmap_serve_handle_over( instance: srv2_lab_dashboard_instance(), - method_label: method, + plan: roadmap_authority_projection(), + daily_body: DailyBodyRenderedUnderThisPlan, + method: method, path: path, body: body, tailscale_identity: tailscale_identity, release_revision: release_revision, - )) + ) } diff --git a/dag/gunbc/roadmap/roadmap_served_observation.dag b/dag/gunbc/roadmap/roadmap_served_observation.dag index 7eb190e860d..400aa0f5f05 100644 --- a/dag/gunbc/roadmap/roadmap_served_observation.dag +++ b/dag/gunbc/roadmap/roadmap_served_observation.dag @@ -16,11 +16,12 @@ import extdeps.languages.json.parse { } import gunbc.host_layout { instance_receipts_dir } import gunbc.roadmap_dashboard_instance { HostDashboardInstance } -import gunbc.roadmap_page { roadmap_daily_workspace_page_for_authority_observed } +import gunbc.roadmap_page { roadmap_daily_workspace_page_for_projection_observed } +import gunbc.roadmap_authority { RoadmapAuthorityProjection, roadmap_authority_projection } import gunbc.roadmap_site_surface_render { page_render_refusal_body, site_artifact_digest } import gunbc.roadmap_belt_actuate { BeltPassOutcome, BeltPassRecorded, BeltPassFailed, - belt_launch_host_standing_for_page, + belt_launch_host_standing_for_page_over, belt_sessions_observe_for_instance, belt_sessions_observed_json, belt_sessions_http_status, belt_attempts_observe_for_instance, belt_attempts_observed_json, belt_attempts_http_status, belt_workflow_attempts_observe_for_instance, @@ -159,14 +160,17 @@ fn served_observation_status_of_label(label: String) -> ServedObservationStatusD else { ServedObservationStatusUnknown { label: label } } } -fn served_observation_daily_surface_for_instance(instance: HostDashboardInstance, observed: BeltWorkflowAttempts) -> ServedObservationSurface { - let launch = belt_launch_host_standing_for_page(instance: instance) +// The daily page is RENDERED HERE, at the tick, and only read back at request time -- so this is +// where the plan a snapshot is about has to arrive. It is the same parameter the serve entry takes, +// travelling the other route into the same page fold. +fn served_observation_daily_surface_over(instance: HostDashboardInstance, plan: RoadmapAuthorityProjection, observed: BeltWorkflowAttempts) -> ServedObservationSurface { + let launch = belt_launch_host_standing_for_page_over(instance: instance, plan: plan) let standings = roadmap_standings_read(layout: roadmap_event_carrier_layout_for_instance(instance: instance)) let page = match observed { WorkflowAttemptsObserved { attempts } => - roadmap_daily_workspace_page_for_authority_observed(attempts: attempts, attempts_refused: none, standings: standings, launch: launch) + roadmap_daily_workspace_page_for_projection_observed(proj: plan, attempts: attempts, attempts_refused: none, standings: standings, launch: launch) WorkflowAttemptsRefused { reason } => - roadmap_daily_workspace_page_for_authority_observed(attempts: [], attempts_refused: Present { value: reason }, standings: standings, launch: launch) + roadmap_daily_workspace_page_for_projection_observed(proj: plan, attempts: [], attempts_refused: Present { value: reason }, standings: standings, launch: launch) } match try_serialize_html_source(node: page) { EmitOk { html } => ServedObservationSurface { kind: DailyPage, status: 200, body: html } @@ -194,12 +198,12 @@ fn served_observation_sessions_surface_for_instance(instance: HostDashboardInsta // The workflow attempts are observed ONCE per tick and shared by the two surfaces that project them // (one observing authority, two projections), so the walk over dispatch worktrees happens once. -fn served_observation_snapshot_observe_for_instance(instance: HostDashboardInstance, observed_at: String) -> ServedObservationSnapshot { +fn served_observation_snapshot_observe_over(instance: HostDashboardInstance, plan: RoadmapAuthorityProjection, observed_at: String) -> ServedObservationSnapshot { let observed = belt_workflow_attempts_observe_for_instance(instance: instance) ServedObservationSnapshot { observed_at: observed_at, surfaces: [ - served_observation_daily_surface_for_instance(instance: instance, observed: observed), + served_observation_daily_surface_over(instance: instance, plan: plan, observed: observed), served_observation_attempts_surface_for_instance(instance: instance), served_observation_workflow_surface_for_instance(instance: instance, observed: observed), served_observation_sessions_surface_for_instance(instance: instance), @@ -399,10 +403,18 @@ fn served_observation_write_for_instance(instance: HostDashboardInstance, snapsh } } -fn served_observation_observe_and_write_for_instance(instance: HostDashboardInstance, observed_at: String) -> BeltPassOutcome { +fn served_observation_observe_and_write_over(instance: HostDashboardInstance, plan: RoadmapAuthorityProjection, observed_at: String) -> BeltPassOutcome { served_observation_write_for_instance( instance: instance, - snapshot: served_observation_snapshot_observe_for_instance(instance: instance, observed_at: observed_at), + snapshot: served_observation_snapshot_observe_over(instance: instance, plan: plan, observed_at: observed_at), + ) +} + +fn served_observation_observe_and_write_for_instance(instance: HostDashboardInstance, observed_at: String) -> BeltPassOutcome { + served_observation_observe_and_write_over( + instance: instance, + plan: roadmap_authority_projection(), + observed_at: observed_at, ) } diff --git a/dag/gunbc/roadmap/roadmap_static_site.dag b/dag/gunbc/roadmap/roadmap_static_site.dag index 41a550ff5e2..e8bebf42dc2 100644 --- a/dag/gunbc/roadmap/roadmap_static_site.dag +++ b/dag/gunbc/roadmap/roadmap_static_site.dag @@ -28,8 +28,12 @@ import gunbc.roadmap_site_surface_render { healthz_body_from_surface_artifacts, healthz_body_with_release_identity, } -import gunbc.roadmap_authority { expected_roadmap_md, authored_merged_prs, roadmap_authority } -import gunbc.roadmap_spawner { roadmap_dispatch_file_content } +import gunbc.roadmap_authority { + expected_roadmap_md_for_projection, + RoadmapAuthorityProjection, roadmap_authority_projection, + authored_merged_prs, +} +import gunbc.roadmap_spawner { roadmap_dispatch_file_content_for_projection } import gunbc.roadmap_page { roadmap_page_for_authority, roadmap_daily_workspace_page_for_authority } import gunbc.roadmap_component { dispatch_client_js_source, roadmap_dispatch_asset_path } import gunbc.fleet_intent_network { fleet_intent_network } @@ -99,12 +103,26 @@ data roadmap_site_readback_script_scaffold: Disposition = Scaffold { // is ~18 ms for the 223 KB roadmap page and ~15 ms for the daily page, so the added per-probe cost // is tens of milliseconds against a poll bound in the tens of seconds. +// THE PLAN IS A PARAMETER, AND THE NULLARY IS ONE BINDING OF IT. Both text bodies are projections +// of a roadmap authority, so the fold takes the projected plan and the zero-argument form supplies +// the public one. A caller serving a different plan -- an entry function in another repository -- +// reaches the same fold with its own projection rather than a second copy of these bodies, and a +// plan that failed to project arrives as RoadmapAuthorityProjectionRefused and refuses through the +// same arm the public plan would. +fn roadmap_site_roadmap_md_body_over(plan: RoadmapAuthorityProjection) -> String { + expected_roadmap_md_for_projection(proj: plan) +} + fn roadmap_site_roadmap_md_body() -> String { - expected_roadmap_md() + roadmap_site_roadmap_md_body_over(plan: roadmap_authority_projection()) +} + +fn roadmap_site_dispatch_json_body_over(plan: RoadmapAuthorityProjection) -> String { + roadmap_dispatch_file_content_for_projection(proj: plan) } fn roadmap_site_dispatch_json_body() -> String { - roadmap_dispatch_file_content() + roadmap_site_dispatch_json_body_over(plan: roadmap_authority_projection()) } fn roadmap_site_roadmap_md_artifact() -> SiteArtifact { diff --git a/dag/test/claim/roadmap/roadmap_serve_witness_test.dag b/dag/test/claim/roadmap/roadmap_serve_witness_test.dag index 88dfd1ba0c3..34523b8260e 100644 --- a/dag/test/claim/roadmap/roadmap_serve_witness_test.dag +++ b/dag/test/claim/roadmap/roadmap_serve_witness_test.dag @@ -20,6 +20,8 @@ import gunbc.roadmap_serve { roadmap_serve_invoke, roadmap_serve_respond, roadmap_serve_respond_for_instance, + roadmap_serve_respond_over, + ServedDailyBodyAuthority, DailyBodyRenderedUnderThisPlan, DailyBodyAuthorityUnknown, belt_dispatch_status, } import gunbc.roadmap_belt_actuate { @@ -50,6 +52,17 @@ import extdeps.http.server { } import extdeps.uri_path { PathParamBinding, path_param_value } import std.types { String, Int, Bool, List, HttpMethod, GET, POST, PUT } +import gunbc.roadmap_authority { + RoadmapAuthorityProjection, RoadmapAuthorityProjected, RoadmapAuthorityProjectionRefused, +} +import gunbc.roadmap_document { RoadmapDocument, RoadmapSection } +import gunbc.roadmap_page { roadmap_daily_workspace_page_for_projection_observed } +import gunbc.roadmap.roadmap_event_log { StandingsUnobserved } +import gunbc.roadmap_launch_admission { launch_host_unobserved_static_render } +import gunbc.roadmap_site_surface_render { roadmap_site_roadmap_url_path, roadmap_site_dispatch_url_path, roadmap_site_daily_url_path } +import gunbc.v1_deletion_plan { v1_exit_finish_lines, v1_finish_lines_accepted_count } +import gunbc.roadmap_model { RoadmapNodeId } +import extdeps.languages.html { EmitOk, EmitRejected, try_serialize_html_source } // Test-local extraction: a Refused build yields the EMPTY table, so every selection witness below // goes RED (nothing selects) — the discriminating direction; the production path never does this @@ -381,3 +394,197 @@ test fn an_absent_identity_arrives_at_the_handler_as_absent() -> Bool { string_contains(s: r.body, pattern: "identity: \n") && !string_contains(s: r.body, pattern: "briansrls") } + +// ── The plan authority is a parameter ─────────────────────────────────────────────────────────── +// +// THE DISCRIMINATING DIRECTION IS THE NEGATIVE. Asserting that a caller-supplied plan appears in +// the response would stay green if a surface under the route ALSO read the public carrier and +// concatenated both; asserting that the public roadmap's own section title is ABSENT is what goes +// red the moment any consumer below the parameterized fold reaches past its parameter to +// roadmap_authority_projection(). That is the whole claim of the seam: one response, one plan. +// +// THE PATHS ARE CITED, NEVER SPELLED. The first cut of these witnesses typed "/roadmap.md" and +// "/dispatch.json"; neither is a route, so all three asked an unrouted path and asserted nothing +// (review 63317; the operator confirmed the 404s against a running instance). A witness that +// spells its own copy of a route is a second authority for it, and it rots exactly that way. These +// read the same declarations gunbc.roadmap_serve now builds its route table from, so a renamed +// route moves the table and the witness together. + +fn caller_supplied_plan_section_title() -> String { "A plan supplied by the caller" } + +// The public roadmap's own section title, from gunbc.roadmap_authority active_section_for_acceptance. +// Its presence in a response rendered over a caller-supplied plan IS the leak. +fn public_plan_section_title() -> String { "Active deliverables" } + +fn caller_supplied_plan_fixture() -> RoadmapAuthorityProjection { + RoadmapAuthorityProjected { + doc: RoadmapDocument { + preamble: [], + lead_lanes: [], + sections: [ + RoadmapSection { title: caller_supplied_plan_section_title(), elements: [] }, + ], + }, + accepted: [], + } +} + +fn serve_over_plan(plan: RoadmapAuthorityProjection, path: String) -> ServeHttpResponse { + serve_over_plan_declaring(plan: plan, daily_body: DailyBodyRenderedUnderThisPlan, path: path) +} + +fn serve_over_plan_declaring( + plan: RoadmapAuthorityProjection, + daily_body: ServedDailyBodyAuthority, + path: String, +) -> ServeHttpResponse { + roadmap_serve_respond_over( + instance: srv2_preview_dashboard_instance(), + plan: plan, + daily_body: daily_body, + method_label: "GET", + path: path, + body: "", + tailscale_identity: "", + release_revision: deploy_witness_release_revision, + ) +} + +test fn witness_roadmap_md_answers_from_the_supplied_plan() -> Bool { + let r = serve_over_plan( + plan: caller_supplied_plan_fixture(), + path: roadmap_site_roadmap_url_path as String, + ) + r.status == 200 + && string_contains(s: r.body, pattern: caller_supplied_plan_section_title()) + && !string_contains(s: r.body, pattern: public_plan_section_title()) +} + +test fn witness_dispatch_json_answers_from_the_supplied_plan() -> Bool { + let r = serve_over_plan( + plan: caller_supplied_plan_fixture(), + path: roadmap_site_dispatch_url_path as String, + ) + r.status == 200 + && !string_contains(s: r.body, pattern: public_plan_section_title()) +} + +// A plan that failed to project refuses in ITS OWN vocabulary rather than serving an empty +// roadmap: the detail the caller handed over is what the reader sees. +test fn witness_supplied_plan_refusal_travels_to_the_wire() -> Bool { + let detail = "the caller's plan carrier could not be read" + let md = serve_over_plan( + plan: RoadmapAuthorityProjectionRefused { detail: detail }, + path: roadmap_site_roadmap_url_path as String, + ) + let dispatch = serve_over_plan( + plan: RoadmapAuthorityProjectionRefused { detail: detail }, + path: roadmap_site_dispatch_url_path as String, + ) + string_contains(s: md.body, pattern: "# roadmap unavailable") + && string_contains(s: md.body, pattern: detail) + && !string_contains(s: md.body, pattern: public_plan_section_title()) + && string_contains(s: dispatch.body, pattern: "\"refused\": true") + && string_contains(s: dispatch.body, pattern: detail) +} + +// A CONTROL FOR THE CONTROL. The three witnesses above are claims about the PLAN, and a wrong path +// would make every one of them vacuous while looking identical to a pass on the negative +// assertions. This one asks an unrouted path and requires the 404, so "the responder answered from +// the supplied plan" stays distinguishable from "the responder never reached a handler". +test fn witness_an_unrouted_path_is_refused_not_answered() -> Bool { + let r = serve_over_plan(plan: caller_supplied_plan_fixture(), path: "/roadmap.md") + r.status == 404 +} + +// ── The DAILY surface, which is where the seam leaked ─────────────────────────────────────────── +// +// WHAT THIS PROBE IS, AND WHAT IT IS NOT. It is a composition check over +// roadmap_daily_workspace_page_for_projection_observed on both arms. It is NOT the control for the +// leak that review 63317 found, and the first version of this block claimed it was. +// +// The claim was tested and it was false. With the leak deliberately restored in an isolated +// worktree -- the refused arm routed back through the fold that read +// accepted_roadmap_node_ids_projection() -- this witness still PASSED. The reason is structural, +// not a weak assertion: under the hermetic witness route the carrier read REFUSES, that fold takes +// its own refused arm, and it produces the same empty accepted set a clean render produces. No +// input reachable from here distinguishes the two, so the RED is not authorable and no stronger +// assertion could have made it so. +// +// DESIGN 4b: a check whose RED cannot be authored is not a weak wall, it is a decoration, and worse +// than absent because it gets cited as coverage. So the defect was closed by CONSTRUCTION instead +// (gunbc.roadmap_page: the ambient-reading fold is deleted, and every caller supplies its accepted +// set), and this block says plainly what it still earns: that both arms render, that a refused plan +// carries the CALLER's detail rather than an empty public roadmap, and that the v1-exit progress +// count is the one the supplied plan implies. The count is cited from v1_finish_lines_accepted_count +// and v1_exit_finish_lines rather than transcribed. +// +// The negative used on the route witnesses above would be decoration here for a second reason: the +// daily page renders work rows and bands, never the roadmap's section headings, so its absence is +// true of a clean render too. + +fn v1_exit_progress_count_text(accepted_ids: List) -> String { + join([ + to_string(v1_finish_lines_accepted_count(accepted: accepted_ids)), + " of ", + to_string(count(v1_exit_finish_lines())), + " finish lines complete", + ], "") +} + +fn daily_page_html_over_plan(plan: RoadmapAuthorityProjection) -> String { + match try_serialize_html_source(node: roadmap_daily_workspace_page_for_projection_observed( + proj: plan, + attempts: [], + attempts_refused: none, + standings: StandingsUnobserved { reason: "witness render: the event carrier is not consulted" }, + launch: launch_host_unobserved_static_render(), + )) { + EmitOk { html } => html + EmitRejected { reason } => reason + } +} + +test fn witness_daily_page_answers_from_the_supplied_plan() -> Bool { + let projected = daily_page_html_over_plan(plan: caller_supplied_plan_fixture()) + let refused = daily_page_html_over_plan( + plan: RoadmapAuthorityProjectionRefused { detail: "the caller's plan carrier could not be read" }, + ) + string_contains(s: projected, pattern: v1_exit_progress_count_text(accepted_ids: [])) + && string_contains(s: refused, pattern: "the caller's plan carrier could not be read") + && string_contains(s: refused, pattern: v1_exit_progress_count_text(accepted_ids: [])) +} + +// ── The route the plan parameter CANNOT reach refuses instead of answering ─────────────────────── +// +// DESIGN 4b puts silent wrongness outside the ladder and forbids it outright, so the plan parameter +// may not create a path where / answers 200 from a body rendered under an authority nobody can +// name. The agreement is a declared fact of the call, and a caller that cannot declare it is +// refused on that ONE route (review 63390). This is the executing evidence for that arm, and for +// its other half: refusing / must not cost the routes whose plan DOES reach them. + +test fn witness_undeclared_daily_body_refuses_rather_than_answering() -> Bool { + let r = serve_over_plan_declaring( + plan: caller_supplied_plan_fixture(), + daily_body: DailyBodyAuthorityUnknown, + path: roadmap_site_daily_url_path as String, + ) + r.status == 503 + && string_contains(s: r.body, pattern: "carries no identity of the authority it came from") + && string_contains(s: r.body, pattern: "served_observation_observe_and_write_over") + && string_contains(s: r.body, pattern: "a_prerendered_body_carries_no_identity_of_its_source") +} + +// THE POSITIVE CONTROL, without which the refusal above is satisfiable by refusing everything: a +// caller that cannot vouch for the daily body still gets every other route answered from its own +// plan, and the refusal is located on / alone. +test fn witness_undeclared_daily_body_costs_no_other_route() -> Bool { + let md = serve_over_plan_declaring( + plan: caller_supplied_plan_fixture(), + daily_body: DailyBodyAuthorityUnknown, + path: roadmap_site_roadmap_url_path as String, + ) + md.status == 200 + && string_contains(s: md.body, pattern: caller_supplied_plan_section_title()) + && !string_contains(s: md.body, pattern: public_plan_section_title()) +}