fix(web): label current Ticket approval from requirement attestation
T-716 MR seq3 CURRENT_REQUIREMENT_APPROVAL_USES_INTEGRATION_PROOF: derive the requirement approval label from review_after_rescope rather than approved_current_subject. Preserve separate persisted integration/source approval display. Strengthen the Web regression for approved integration with stale current requirements and recovery by exact current attestation; require the Ticket route to render that tested status projection. Validation: 28 focused Deno decoder/status/resource/route-reuse tests; deno task check (0 errors/warnings); root cargo check; cargo fmt --all -- --check; git diff --check HEAD. Rust contracts unchanged from validated source14fea520.
This commit is contained in:
@@ -7,6 +7,7 @@ import type { TicketMergeRequestSummary } from "#lib/generated/ticket-api.ts";
|
||||
import { fixtureDetail } from "./home/dashboard.test-fixtures.ts";
|
||||
import { parseTicketDetail } from "./api/ticket-browser.ts";
|
||||
import {
|
||||
currentRequirementApprovalStatus,
|
||||
sourceReviewFreshness,
|
||||
summarySourceReviewStatus,
|
||||
} from "./merge-request-status.ts";
|
||||
@@ -91,6 +92,13 @@ Deno.test("done Ticket can retain immutable approval while current requirement e
|
||||
state: "done",
|
||||
evidence: {
|
||||
...fixtureDetail().evidence,
|
||||
has_merge_request: true,
|
||||
has_current_subject_ref: true,
|
||||
has_commit: true,
|
||||
has_review_request: true,
|
||||
review_status: "pending",
|
||||
approved_current_subject: true,
|
||||
review_after_rescope: false,
|
||||
missing: ["review_after_rescope"],
|
||||
},
|
||||
merge_requests: [{
|
||||
@@ -101,6 +109,26 @@ Deno.test("done Ticket can retain immutable approval while current requirement e
|
||||
});
|
||||
assertEquals(ticket.state, "done");
|
||||
assertEquals(ticket.evidence.complete_for_integration, false);
|
||||
assertEquals(
|
||||
currentRequirementApprovalStatus(ticket.evidence),
|
||||
"not established",
|
||||
);
|
||||
const recovered = parseTicketDetail({
|
||||
...ticket,
|
||||
evidence: {
|
||||
...ticket.evidence,
|
||||
review_after_rescope: true,
|
||||
review_status: "approved",
|
||||
complete_for_integration: true,
|
||||
missing: [],
|
||||
},
|
||||
});
|
||||
assertEquals(recovered.evidence.approved_current_subject, true);
|
||||
assertEquals(
|
||||
currentRequirementApprovalStatus(recovered.evidence),
|
||||
"approved",
|
||||
);
|
||||
assertEquals(recovered.state, "done");
|
||||
assertEquals(
|
||||
summarySourceReviewStatus(ticket.merge_requests[0]!),
|
||||
"Integration approval recorded for immutable merged source source-1.",
|
||||
@@ -118,7 +146,7 @@ Deno.test("Ticket route separates current requirement evidence from immutable in
|
||||
const required of [
|
||||
"Current requirement evidence",
|
||||
"ticket.evidence.complete_for_integration",
|
||||
"ticket.evidence.approved_current_subject",
|
||||
"Current requirement approval:</strong> {currentRequirementApprovalStatus(ticket.evidence)}",
|
||||
"ticket.evidence.missing",
|
||||
"summarySourceReviewStatus(mergeRequest)",
|
||||
"Immutable integration evidence",
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { TicketMergeRequestSummary } from "#lib/generated/ticket-api.ts";
|
||||
import type {
|
||||
TicketEvidenceSummary,
|
||||
TicketMergeRequestSummary,
|
||||
} from "#lib/generated/ticket-api.ts";
|
||||
import type {
|
||||
MergeRequestDetail,
|
||||
MergeRequestThreadEvent,
|
||||
@@ -89,6 +92,14 @@ export function sourceReviewFreshness(
|
||||
return `Fresh source review required: no effective verdict exists for ${source}.`;
|
||||
}
|
||||
|
||||
// Source/integration approval can survive rescope; only this exact revision
|
||||
// and linked-result attestation approves the current Ticket requirements.
|
||||
export function currentRequirementApprovalStatus(
|
||||
evidence: TicketEvidenceSummary,
|
||||
): string {
|
||||
return evidence.review_after_rescope ? "approved" : "not established";
|
||||
}
|
||||
|
||||
export function summarySourceReviewStatus(
|
||||
mergeRequest: TicketMergeRequestSummary,
|
||||
): string {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
parseTicketRoleAssignmentMutationResponse,
|
||||
} from "#lib/workspace/api/ticket-browser.ts";
|
||||
import { mergeRequestPagePath } from "#lib/workspace/api/merge-requests.ts";
|
||||
import { summarySourceReviewStatus } from "#lib/workspace/merge-request-status.ts";
|
||||
import { currentRequirementApprovalStatus, summarySourceReviewStatus } from "#lib/workspace/merge-request-status.ts";
|
||||
import {
|
||||
relationLabel,
|
||||
TICKET_STATES,
|
||||
@@ -686,7 +686,7 @@
|
||||
<section class="ticket-control-card">
|
||||
<header><h2>Current requirement evidence</h2></header>
|
||||
<p><strong>Current requirements:</strong> {ticket.evidence.complete_for_integration ? "satisfied for integration" : "not satisfied for integration"}.</p>
|
||||
<p><strong>Current requirement approval:</strong> {ticket.evidence.approved_current_subject ? "approved" : "not established"}.</p>
|
||||
<p><strong>Current requirement approval:</strong> {currentRequirementApprovalStatus(ticket.evidence)}.</p>
|
||||
{#if ticket.evidence.missing.length > 0}
|
||||
<ul>
|
||||
{#each ticket.evidence.missing as missing}<li>{missing}</li>{/each}
|
||||
|
||||
Reference in New Issue
Block a user