fix: add dev report lifecycle contract (#85)

Co-authored-by: root <root@lyon.remote>
This commit is contained in:
Lyon
2026-05-22 14:33:10 +08:00
committed by GitHub
parent 1af787f63f
commit db9d6ae6e3
21 changed files with 344 additions and 21 deletions
+2
View File
@@ -10,6 +10,7 @@ import {
DEV_DB_ENV_CONTRACT,
summarizeDbContract
} from "../../internal/cloud/db-contract.mjs";
import { activeReportLifecycle } from "../../internal/dev-report-lifecycle.mjs";
import { DEV_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../../internal/protocol/index.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -970,6 +971,7 @@ export async function runDevDeployApply(argv, io = {}) {
acceptanceLevel: "dev_deploy_apply",
devOnly: true,
prodDisabled: true,
reportLifecycle: activeReportLifecycle("Current DEV deploy apply report; active public API/health endpoint is 16667 and browser endpoint is 16666."),
status,
generatedAt: new Date().toISOString(),
namespace,
@@ -6,6 +6,7 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import { DEV_DB_ENV_CONTRACT, summarizeDbContract } from "../../internal/cloud/db-contract.mjs";
import { activeReportLifecycle } from "../../internal/dev-report-lifecycle.mjs";
import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../../internal/protocol/index.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -118,6 +119,7 @@ async function createDevGateReport(edgeHealth) {
acceptanceLevel: "dev_edge_health",
devOnly: true,
prodDisabled: true,
reportLifecycle: activeReportLifecycle("Current DEV edge-health report; deprecated public 6666/6667 endpoints are not valid active evidence."),
status,
generatedAt: edgeHealth.generatedAt,
namespace,
@@ -4,6 +4,7 @@ import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { activeReportLifecycle, reportIsHistorical, reportLifecycleState } from "../../internal/dev-report-lifecycle.mjs";
import { DEV_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../../internal/protocol/index.mjs";
export const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -33,6 +34,8 @@ const blockerTypes = new Set([
"observability_blocker",
"safety_blocker"
]);
const historicalLifecycleSummary =
"Historical report retained for evidence provenance; it is not active green DEV evidence.";
const reportPaths = Object.freeze({
devPreflight: "reports/dev-gate/dev-preflight-report.json",
@@ -275,6 +278,7 @@ function sourceEntry(entry) {
level: entry.level,
status: entry.status,
category: entry.category,
lifecycleState: entry.lifecycleState ?? "active",
sources: entry.sources,
commands: entry.commands,
summary: entry.summary
@@ -282,18 +286,21 @@ function sourceEntry(entry) {
}
function reportEvidence({ milestone, level, report, status, category, summary, evidence = [], commands = [] }) {
const lifecycleState = reportLifecycleState(report);
const historical = lifecycleState === "historical";
return {
milestone,
issue: report.issue,
taskId: report.taskId ?? report.reportKind,
reportPath: report.path,
commitId: short(report.commitId ?? report.target?.commitId),
level,
status,
lifecycleState,
level: historical ? "BLOCKED" : level,
status: historical && status === "pass" ? "blocked" : status,
category,
commands,
evidence,
summary
summary: historical ? `${summary} ${historicalLifecycleSummary}` : summary
};
}
@@ -485,6 +492,19 @@ function collectM5Evidence(reports) {
function collectBlockers(reports) {
const blockers = [];
for (const report of Object.values(reports)) {
if (reportIsHistorical(report)) {
blockers.push({
id: `${report.taskId ?? report.reportKind ?? "report"}-historical:${report.path}`,
priority: "P2",
type: "observability_blocker",
scope: `${report.taskId ?? report.reportKind ?? "report"}-historical`,
status: "open",
source: report.path,
sourceIssue: report.issue,
summary: `${report.taskId ?? report.reportKind ?? "Report"} is historical/deprecated and must be refreshed before it can support active DEV evidence. ${historicalLifecycleSummary}`,
nextTask: "Regenerate the report as active DEV evidence or keep the historical snapshot in an archival path."
});
}
for (const blocker of report.blockers ?? []) {
if (isStaleLegacyIngressBlocker(blocker, report, reports)) {
continue;
@@ -593,6 +613,7 @@ function groupByLevel(evidence, blockers) {
milestone: item.milestone,
issue: item.issue,
taskId: item.taskId,
lifecycleState: item.lifecycleState,
status: item.status,
category: item.category,
reportPath: item.reportPath,
@@ -780,6 +801,9 @@ export async function buildReport() {
endpoint: DEV_ENDPOINT,
devOnly: true,
prodDisabled: true,
reportLifecycle: activeReportLifecycle(
"Current M5 evidence aggregator report; source, local, and dry-run evidence are not DEV-LIVE acceptance."
),
safety: {
reportOnly: true,
noDeploy: true,
@@ -797,6 +821,7 @@ export async function buildReport() {
path: report.path,
issue: report.issue,
taskId: report.taskId ?? report.reportKind,
lifecycleState: reportLifecycleState(report),
status: primaryStatus(report),
commitId: short(report.commitId ?? report.target?.commitId)
}
+2
View File
@@ -10,6 +10,7 @@ import {
buildDbHealthContract,
summarizeDbContract
} from "../../internal/cloud/db-contract.mjs";
import { activeReportLifecycle } from "../../internal/dev-report-lifecycle.mjs";
import { DEV_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../../internal/protocol/index.mjs";
import { probeRegistryCapabilities } from "./registry-capabilities.mjs";
@@ -1095,6 +1096,7 @@ function makeReport(args, targetCommit, targetShortCommit, reporter, artifactIde
mode: "read-only",
devOnly: true,
prodDisabled: true,
reportLifecycle: activeReportLifecycle("Current read-only DEV preflight report; source, local, and dry-run checks are not DEV-LIVE acceptance."),
forbiddenActions,
validationCommands: [
"node --check scripts/dev-gate-preflight.mjs",