docs: refresh DEV gate evidence layering

This commit is contained in:
HWLAB Code Queue
2026-05-22 07:26:40 +00:00
parent 8e89409dda
commit e7cc38147e
10 changed files with 1116 additions and 399 deletions
@@ -113,15 +113,20 @@ async function run(command, args = [], options = {}) {
timeout: options.timeoutMs ?? 5000,
maxBuffer: 1024 * 1024
});
return {
const probe = {
ok: true,
command: commandText(command, args),
exitCode: 0,
stdout: redacted(result.stdout.trim()),
stderr: redacted(result.stderr.trim())
};
Object.defineProperty(probe, "rawStdout", {
value: result.stdout.trim(),
enumerable: false
});
return probe;
} catch (error) {
return {
const probe = {
ok: false,
command: commandText(command, args),
exitCode: typeof error.code === "number" ? error.code : 1,
@@ -129,6 +134,11 @@ async function run(command, args = [], options = {}) {
stderr: redacted(String(error.stderr ?? "").trim()),
error: oneLine(error.message)
};
Object.defineProperty(probe, "rawStdout", {
value: String(error.stdout ?? "").trim(),
enumerable: false
});
return probe;
}
}
@@ -239,9 +249,10 @@ async function collectSshBridge(binaries) {
}
function parseJsonProbe(probe) {
if (!probe.ok || !probe.stdout) return null;
const raw = probe.rawStdout ?? probe.stdout;
if (!probe.ok || !raw) return null;
try {
return JSON.parse(probe.stdout);
return JSON.parse(raw);
} catch {
return null;
}
@@ -407,7 +418,7 @@ function buildBlockers({ binaries, kubeconfig, sshBridge, cluster }) {
nextTask: "Mount a read-only kubeconfig for hwlab-dev, or document the approved k3s local kubeconfig path without exposing token material."
});
}
if (!sshBridge.configured) {
if (!sshBridge.configured && !cluster.readable) {
addBlocker(blockers, {
type: "environment_blocker",
scope: "d601-maintenance-ssh-bridge",
+239 -20
View File
@@ -5,7 +5,7 @@ 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";
import { DEV_ENDPOINT, DEV_FRONTEND_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../../internal/protocol/index.mjs";
export const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
@@ -42,6 +42,7 @@ const reportPaths = Object.freeze({
devDeploy: "reports/dev-gate/dev-deploy-report.json",
devArtifacts: "reports/dev-gate/dev-artifacts.json",
devEdgeHealth: "reports/dev-gate/dev-edge-health.json",
devM2Smoke: "reports/dev-gate/dev-m2-deploy-smoke-active.json",
devM3Hardware: "reports/dev-gate/dev-m3-hardware-loop.json",
devM4Agent: "reports/dev-gate/dev-m4-agent-loop.json",
devM5Gate: "reports/dev-gate/dev-mvp-gate-report.json",
@@ -189,6 +190,19 @@ function hasBlocker(blockers, predicate) {
return blockers.some(predicate);
}
function isRouteTransportBlocker(blocker) {
const scope = blocker.scope ?? "";
return scope === "m2-public-endpoints" ||
scope === "dev-edge" ||
scope === "dev-edge-health" ||
scope === "hwlab-router" ||
scope === "hwlab-tunnel-client" ||
scope === "hwlab-edge-proxy" ||
scope.includes("edge-frp") ||
scope.includes("ingress") ||
scope.includes("frp");
}
function applyPriority(blocker) {
if (blocker.scope === "base-image") {
return {
@@ -234,6 +248,16 @@ function applyPriority(blocker) {
};
}
if (blocker.scope === "hwlab-dev-readonly-rbac") {
return {
...blocker,
priority: "P1",
unblockOrder: 4,
unblocks: [issue(34), issue(33), issue(36), issue(38), issue(39)],
rationale: "D601 has a client path, but read-only hwlab-dev pods/services/configmaps must be observable before live acceptance evidence can be trusted."
};
}
if (blocker.scope.includes("cloud-api-db")) {
return {
...blocker,
@@ -244,6 +268,16 @@ function applyPriority(blocker) {
};
}
if (blocker.scope === "db-live") {
return {
...blocker,
priority: "P1",
unblockOrder: 5,
unblocks: [issue(37), issue(39)],
rationale: "M4 and M5 cannot claim live agent or MVP evidence until cloud-api /health/live proves DB readiness with redacted live evidence."
};
}
if (isEdgeOrFrpBlocker(blocker)) {
return {
...blocker,
@@ -254,6 +288,16 @@ function applyPriority(blocker) {
};
}
if (blocker.scope === "m3-hardware-loop-runtime") {
return {
...blocker,
priority: "P0",
unblockOrder: 6,
unblocks: [issue(38), issue(39), issue(64)],
rationale: "M3 remains blocked until the real DEV hardware trusted loop proves DO1 -> patch-panel -> DI1 with operation, trace, audit, and evidence identifiers."
};
}
return {
...blocker,
priority: blocker.priority ?? "P3",
@@ -264,11 +308,7 @@ function applyPriority(blocker) {
}
function isEdgeOrFrpBlocker(blocker) {
return blocker.scope.includes("edge") ||
blocker.scope.includes("ingress") ||
blocker.scope.includes("frp") ||
blocker.summary.includes(":16667") ||
blocker.summary.includes("16667");
return isRouteTransportBlocker(blocker);
}
function sourceEntry(entry) {
@@ -309,9 +349,11 @@ function collectM2Evidence(reports) {
const deploy = reports.devDeploy;
const artifacts = reports.devArtifacts;
const edge = reports.devEdgeHealth;
const m2Smoke = reports.devM2Smoke;
const d601 = reports.d601Observability;
const artifactIdentity = preflight.artifactIdentity;
const edgeLive = hasCurrentLiveEdgeEvidence(edge);
const m2EndpointLive = hasCurrentM2EndpointEvidence(m2Smoke);
return [
reportEvidence({
@@ -352,6 +394,18 @@ function collectM2Evidence(reports) {
commands: artifacts.validationCommands,
summary: "Artifact publish preflight exists but is blocked before any real image publish."
}),
reportEvidence({
milestone: "M2",
level: m2EndpointLive ? "DEV-LIVE" : "BLOCKED",
report: m2Smoke,
status: m2Smoke.runtimeSmoke?.status ?? primaryStatus(m2Smoke),
category: "public-entrypoints-read-only",
evidence: publicEndpointEvidence(m2Smoke),
commands: m2Smoke.devPreconditions?.commands ?? [],
summary: m2EndpointLive
? "Read-only probes prove the frozen public DEV entrypoints on :16666/:16667 are reachable; this is EDGE/ROUTE evidence only."
: "The active M2 public endpoint smoke does not prove the frozen :16666/:16667 entrypoints."
}),
reportEvidence({
milestone: "M2",
level: edgeLive ? "DEV-LIVE" : "SOURCE",
@@ -388,6 +442,7 @@ function collectM2Evidence(reports) {
function collectM3Evidence(reports) {
const m3 = reports.devM3Hardware;
const m5Milestone = reports.devM5Gate.milestones?.find((item) => item.id === "M3");
const liveSummary = m3TrustedLoopSummary(m3);
return [
reportEvidence({
milestone: "M3",
@@ -422,11 +477,20 @@ function collectM3Evidence(reports) {
`evidenceId=${m3.liveOperation?.evidenceId ?? "not_observed"}`
],
commands: ["node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production"],
summary: m3.liveOperation?.summary ?? "No live M3 hardware operation was observed."
summary: liveSummary
})
];
}
function m3TrustedLoopSummary(m3Report) {
const operationSummary = m3Report.liveOperation?.summary ?? "No live M3 hardware operation was observed.";
const blockerSummary = m3Report.blockers?.find((blocker) => blocker.scope === "m3-hardware-loop-runtime")?.summary;
if (statusIsPass(m3Report.liveOperation?.status) || !blockerSummary) {
return operationSummary;
}
return `${operationSummary} Blocker: ${blockerSummary}.`;
}
function collectM4Evidence(reports) {
const m4 = reports.devM4Agent;
return [
@@ -537,6 +601,25 @@ function hasCurrentLiveEdgeEvidence(edgeReport) {
publicHttp.some((probe) => probe.url === `${DEV_ENDPOINT}/health/live` && probe.ok === true && probe.status === 200);
}
function hasCurrentM2EndpointEvidence(m2Report) {
const probes = m2Report?.runtimeSmoke?.probes ?? [];
return m2Report?.endpoint === DEV_ENDPOINT &&
m2Report?.frontendEndpoint === DEV_FRONTEND_ENDPOINT &&
m2Report?.runtimeSmoke?.mode === "live-read-only" &&
m2Report?.runtimeSmoke?.status === "pass" &&
probes.some((probe) => probe.url === `${DEV_ENDPOINT}/health` && probe.ok === true && probe.status === 200) &&
probes.some((probe) => probe.url === `${DEV_ENDPOINT}/health/live` && probe.ok === true && probe.status === 200) &&
probes.some((probe) => probe.url === `${DEV_FRONTEND_ENDPOINT}/` && probe.ok === true && probe.status === 200);
}
function publicEndpointEvidence(m2Report) {
return (m2Report?.runtimeSmoke?.probes ?? []).map((probe) => {
const identity = probe.json?.serviceId ?? probe.title ?? "unknown";
const status = probe.json?.status ?? (probe.ok ? "ok" : "failed");
return `${probe.url} -> HTTP ${probe.status ?? "none"} identity=${identity} status=${status}`;
});
}
function isStaleLegacyIngressBlocker(blocker, sourceReport, reports) {
const text = `${blocker.scope ?? ""} ${blocker.summary ?? ""}`;
const staleLegacyPort = text.includes(deprecatedLegacyPublicEndpoint);
@@ -571,6 +654,7 @@ function deriveMilestones(evidence, blockers) {
const liveItems = items.filter((item) => item.level === "DEV-LIVE");
const highestVisibleLevel = levels.findLast((level) => items.some((item) => item.level === level && level !== "BLOCKED" && statusHasEvidence(item.status))) ?? "BLOCKED";
const hasPassingLive = liveItems.some((item) => statusIsPass(item.status));
const hasBlockedEvidence = items.some((item) => item.level === "BLOCKED" && ["blocked", "failed", "degraded"].includes(item.status));
const milestoneBlockers = blockers.filter((blocker) => {
if (milestone === "M2") return blocker.unblocks.includes(issue(33)) || blocker.unblocks.includes(issue(35)) || blocker.unblocks.includes(issue(36));
if (milestone === "M3") return blocker.unblocks.includes(issue(38));
@@ -578,7 +662,7 @@ function deriveMilestones(evidence, blockers) {
if (milestone === "M5") return blocker.unblocks.includes(issue(39));
return false;
});
const status = milestoneBlockers.length > 0 || (liveItems.length > 0 && !hasPassingLive)
const status = milestoneBlockers.length > 0 || hasBlockedEvidence || (liveItems.length > 0 && !hasPassingLive)
? "blocked"
: worstStatus(items.map((item) => item.status));
@@ -642,7 +726,16 @@ function buildDoD(reports, milestones, blockers) {
const preflight = reports.devPreflight;
const artifactIdentity = preflight.artifactIdentity;
const d601 = reports.d601Observability;
const d601HasClient = d601.environment?.binaries?.kubectl?.available === true ||
d601.environment?.binaries?.k3s?.available === true;
const edgeLive = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth);
const artifactCurrent = artifactIdentity.publishVerified === true &&
artifactIdentity.targetCoverage?.covered !== false &&
artifactIdentity.artifactCatalog?.matchesTarget !== false;
const cloudApiDb = cloudApiDbStatus(reports);
const dbReady = cloudApiDb.ready === true && cloudApiDb.connected === true && cloudApiDb.liveDbEvidence === true;
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
return {
status: blockers.length === 0 && milestones.every((item) => item.status === "pass") ? "green" : "blocked",
@@ -662,9 +755,9 @@ function buildDoD(reports, milestones, blockers) {
},
{
id: "artifact-publish-digests",
status: artifactIdentity.publishVerified ? "pass" : "blocked",
evidenceLevel: artifactIdentity.publishVerified ? "DEV-LIVE" : "BLOCKED",
summary: `artifactState=${artifactIdentity.artifactCatalog.artifactState}, ciPublished=${artifactIdentity.artifactCatalog.ciPublished}, registryVerified=${artifactIdentity.artifactCatalog.registryVerified}, sha256=${artifactIdentity.artifactCatalog.digestCounts.sha256}, not_published=${artifactIdentity.artifactCatalog.digestCounts.notPublished}`
status: artifactCurrent ? "pass" : "blocked",
evidenceLevel: artifactCurrent ? "DEV-LIVE" : "BLOCKED",
summary: `artifactState=${artifactIdentity.artifactCatalog.artifactState}, ciPublished=${artifactIdentity.artifactCatalog.ciPublished}, registryVerified=${artifactIdentity.artifactCatalog.registryVerified}, sha256=${artifactIdentity.artifactCatalog.digestCounts.sha256}, not_published=${artifactIdentity.artifactCatalog.digestCounts.notPublished}, targetCovered=${artifactIdentity.targetCoverage?.covered ?? "unknown"}`
},
{
id: "d601-k3s-observability",
@@ -672,21 +765,39 @@ function buildDoD(reports, milestones, blockers) {
evidenceLevel: d601.cluster?.readable ? "DEV-LIVE" : "BLOCKED",
summary: d601.cluster?.readable
? "D601 hwlab-dev cluster was readable."
: "D601 runner lacks kubectl/k3s/kubeconfig observability for hwlab-dev."
: d601HasClient
? "D601 kubectl/k3s clients are present, but read-only hwlab-dev pods/services/configmaps probes are still blocked."
: "D601 runner lacks kubectl/k3s/kubeconfig observability for hwlab-dev."
},
{
id: "dev-edge-frp-16667",
status: edgeLive && !hasBlocker(blockers, isEdgeOrFrpBlocker) ? "pass" : "blocked",
evidenceLevel: edgeLive && !hasBlocker(blockers, isEdgeOrFrpBlocker) ? "DEV-LIVE" : "BLOCKED",
status: edgeLive && !hasBlocker(blockers, isRouteTransportBlocker) ? "pass" : "blocked",
evidenceLevel: edgeLive && !hasBlocker(blockers, isRouteTransportBlocker) ? "DEV-LIVE" : "BLOCKED",
summary: edgeLive
? "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; old preflight network probe blockers are stale."
? "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; this is route evidence, not DB/M3/M4/M5 acceptance."
: "No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667."
},
{
id: "cloud-api-db-ready",
status: hasBlocker(blockers, (blocker) => blocker.scope.includes("cloud-api-db")) ? "blocked" : "pass",
evidenceLevel: "BLOCKED",
summary: "Manifest-level DB env exists, but live DB health readiness is still blocked/missing."
status: dbReady ? "pass" : "blocked",
evidenceLevel: dbReady ? "DEV-LIVE" : "BLOCKED",
summary: `cloud-api DB status=${cloudApiDb.status}; ready=${cloudApiDb.ready}; connected=${cloudApiDb.connected}; liveDbEvidence=${cloudApiDb.liveDbEvidence}.`
},
{
id: "m3-hardware-trusted-loop",
status: m3Live ? "pass" : "blocked",
evidenceLevel: m3Live ? "DEV-LIVE" : "BLOCKED",
summary: m3Live
? "M3 hardware trusted loop has operation, trace, audit, and evidence identifiers."
: "M3 trusted loop is blocked until res_boxsimu_1:DO1 -> patch-panel -> res_boxsimu_2:DI1 is proven with operation/trace/audit/evidence."
},
{
id: "m4-agent-loop-live",
status: m4Live ? "pass" : "blocked",
evidenceLevel: m4Live ? "DEV-LIVE" : "BLOCKED",
summary: m4Live
? "M4 agent loop live preflight passed."
: "M4 agent loop live path is blocked before accepted agent scheduling/evidence closure."
},
{
id: "m5-mvp-dev-live",
@@ -698,6 +809,99 @@ function buildDoD(reports, milestones, blockers) {
};
}
function cloudApiDbStatus(reports) {
const db = reports.devEdgeHealth.edgeHealth?.contracts?.deploy?.cloudApiDb ?? {};
return {
status: db.status ?? "unknown",
ready: db.ready === true,
connected: db.connected === true || db.liveConnected === true,
configReady: db.configReady === true,
connectionChecked: db.connectionChecked === true,
liveDbEvidence: db.liveDbEvidence === true
};
}
function buildCurrentDevLayering(reports, blockers) {
const m2EndpointLive = hasCurrentM2EndpointEvidence(reports.devM2Smoke);
const edgeLive = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth);
const cloudDb = cloudApiDbStatus(reports);
const dbReady = cloudDb.ready && cloudDb.connected && cloudDb.liveDbEvidence;
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
const artifactIdentity = reports.devPreflight.artifactIdentity;
const artifactCurrent = artifactIdentity.publishVerified === true &&
artifactIdentity.targetCoverage?.covered !== false &&
artifactIdentity.artifactCatalog?.matchesTarget !== false;
const desired = reports.devDeploy.devDeployApply ?? {};
const artifactSourceStates = artifactSourceStateCounts(reports.devArtifacts);
return {
edgeRoute: {
label: "EDGE/ROUTE live",
status: m2EndpointLive || edgeLive ? "pass" : "blocked",
evidenceLevel: m2EndpointLive || edgeLive ? "DEV-LIVE" : "BLOCKED",
summary: m2EndpointLive
? "16666 browser, 16667 /health, and 16667 /health/live returned accepted HWLAB DEV responses in the active M2 read-only smoke."
: "No active read-only public endpoint report proves both 16666 and 16667.",
evidence: publicEndpointEvidence(reports.devM2Smoke),
nextRequired: "Keep this separated from DB readiness, M3/M4 loop evidence, and M5 acceptance."
},
dbLive: {
label: "DB live/degraded",
status: dbReady ? "pass" : "blocked",
evidenceLevel: dbReady ? "DEV-LIVE" : "BLOCKED",
summary: `cloud-api DB status=${cloudDb.status}; configReady=${cloudDb.configReady}; ready=${cloudDb.ready}; connected=${cloudDb.connected}; liveDbEvidence=${cloudDb.liveDbEvidence}.`,
evidence: reports.devM5Gate.devPreconditions?.evidence?.filter((line) => line.includes("/health/live") || line.includes("DB")) ?? [],
nextRequired: "Provide live DB connection evidence through redacted health output; route reachability alone is insufficient."
},
m3HardwareTrustedLoop: {
label: "M3 hardware trusted loop",
status: m3Live ? "pass" : "blocked",
evidenceLevel: m3Live ? "DEV-LIVE" : "BLOCKED",
summary: m3TrustedLoopSummary(reports.devM3Hardware),
evidence: [
`operationId=${reports.devM3Hardware.liveOperation?.operationId ?? "not_observed"}`,
`traceId=${reports.devM3Hardware.liveOperation?.traceId ?? "not_observed"}`,
`auditId=${reports.devM3Hardware.liveOperation?.auditId ?? "not_observed"}`,
`evidenceId=${reports.devM3Hardware.liveOperation?.evidenceId ?? "not_observed"}`
],
nextRequired: "Only a real DEV res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 observation with operation/trace/audit/evidence can clear M3."
},
m4AgentLoop: {
label: "M4 agent loop",
status: m4Live ? "pass" : "blocked",
evidenceLevel: m4Live ? "DEV-LIVE" : "BLOCKED",
summary: reports.devM4Agent.livePreflight?.summary ?? reports.devM4Agent.devPreconditions?.summary ?? "No live M4 observation was recorded.",
evidence: reports.devM4Agent.livePreflight?.evidence ?? [],
nextRequired: "Do not schedule or claim the agent loop as live until DB live and required runtime/evidence preconditions pass."
},
artifactDesiredStateSource: {
label: "artifact/desired-state source",
status: artifactCurrent && desired.conclusion?.status === "ready" ? "pass" : "blocked",
evidenceLevel: artifactCurrent ? "SOURCE" : "BLOCKED",
summary: `artifact targetCovered=${artifactIdentity.targetCoverage?.covered ?? "unknown"}; artifactSource=${short(artifactIdentity.artifactSource?.commitId)}; target=${short(artifactIdentity.source?.commitId)}; desiredApplyMode=${desired.mode ?? "unknown"}; mutationAttempted=${desired.mutationAttempted === true}.`,
evidence: [
`artifactState=${artifactIdentity.artifactCatalog?.artifactState ?? "unknown"}`,
`sourceStates=${artifactSourceStates.sourcePresent} source-present, ${artifactSourceStates.intentionallyDisabled} intentionally-disabled`,
`desiredState=${desired.conclusion?.status ?? "not_reported"} dry-run-only`
],
nextRequired: "Refresh artifact/source coverage for current origin/main and keep desired-state apply separate from read-only route proof."
}
};
}
function artifactSourceStateCounts(artifactReport) {
const counts = { sourcePresent: 0, intentionallyDisabled: 0 };
for (const service of artifactReport.artifactPublish?.services ?? []) {
if (service.sourceState === "source-present") {
counts.sourcePresent += 1;
} else if (service.sourceState === "intentionally-disabled") {
counts.intentionallyDisabled += 1;
}
}
return counts;
}
function buildNextSteps(blockers) {
const byOrder = new Map();
for (const blocker of blockers) {
@@ -737,6 +941,8 @@ function fallbackAction(scope) {
if (scope.includes("artifact")) return "Publish DEV artifacts for every frozen HWLAB service and record immutable registry digests.";
if (scope.includes("edge") || scope.includes("ingress") || scope.includes("frp")) return "Repair frp/master-edge/D601 router path and rerun read-only DEV edge health.";
if (scope.includes("cloud-api-db")) return "Configure DEV cloud-api DB env readiness and rerun health/preflight without exposing secrets.";
if (scope === "db-live") return "Repair DEV cloud-api DB live readiness, then rerun the read-only health and M4 preflight reports without exposing secret values.";
if (scope === "m3-hardware-loop-runtime") return "Prove the real DEV M3 trusted loop res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 with operation, trace, audit, and evidence identifiers.";
if (scope.includes("kubectl") || scope.includes("k3s")) return "Provide read-only kubectl/kubeconfig observability for hwlab-dev.";
return "Resolve the blocker and attach source/local/dry-run/DEV-live evidence at the correct level.";
}
@@ -747,6 +953,8 @@ function evidenceRequiredFor(scope) {
if (scope.includes("artifact") || scope === "ghcr") return "Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID.";
if (scope.includes("kubectl") || scope.includes("k3s")) return "Read-only kubectl/k3s report proving pods/services/configmaps are observable in hwlab-dev without reading Secrets.";
if (scope.includes("cloud-api-db")) return "Cloud API health/live output showing DB env ready and redacted secret references, without secret material.";
if (scope === "db-live") return "Cloud API /health/live output with ready=true, connected=true, liveDbEvidence=true, and redacted secret references.";
if (scope === "m3-hardware-loop-runtime") return "Operation, trace, audit, and evidence IDs from the real DEV DO1 -> patch-panel -> DI1 trusted loop.";
if (scope.includes("edge") || scope.includes("ingress") || scope.includes("frp")) return "Read-only DEV route observation for :16667/frp/edge/router with HWLAB service identity and artifact identity.";
return "A committed report with the exact evidence level and command used.";
}
@@ -787,6 +995,7 @@ export async function buildReport() {
const blockers = collectBlockers(reports);
const milestones = deriveMilestones(evidence, blockers);
const dod = buildDoD(reports, milestones, blockers);
const currentDevLayering = buildCurrentDevLayering(reports, blockers);
const nextSteps = buildNextSteps(blockers);
const report = {
"$schema": "https://hwlab.pikastech.local/schemas/dev-m5-gate-aggregator-v2.schema.json",
@@ -794,7 +1003,7 @@ export async function buildReport() {
reportVersion: "v2",
reportKind: "dev-m5-gate-aggregator",
issue: issue(58),
supports: [issue(7), issue(9), issue(31), issue(33), issue(34), issue(35), issue(36), issue(37), issue(38), issue(39), issue(46)],
supports: [issue(7), issue(9), issue(23), issue(26), issue(31), issue(33), issue(34), issue(35), issue(36), issue(37), issue(38), issue(39), issue(46), issue(64)],
generatedAt: new Date().toISOString(),
generatedFromCommit: gitCommit(),
environment: ENVIRONMENT_DEV,
@@ -832,9 +1041,10 @@ export async function buildReport() {
green: dod.green,
reason: dod.green
? "All #9 DEV DoD checks are green."
: "SOURCE, LOCAL, DRY-RUN, and edge DEV-LIVE evidence exists, but acceptance is still blocked by artifact, observability, DB, and loop evidence gaps."
: "EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, DB live degradation, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight."
},
dod,
currentDevLayering,
milestones,
evidence,
levels: groupByLevel(evidence, blockers),
@@ -862,6 +1072,9 @@ export function formatCheckSummary(report) {
}
export function renderMarkdown(report) {
const layeringLines = Object.entries(report.currentDevLayering)
.map(([, layer]) => `| ${layer.label} | ${layer.status} | ${layer.evidenceLevel} | ${layer.summary} | ${layer.nextRequired} |`)
.join("\n");
const milestoneLines = report.milestones
.map((milestone) => `| ${milestone.id} | ${milestone.status} | ${milestone.highestVisibleLevel} | ${milestone.liveEvidence} | ${milestone.summary} |`)
.join("\n");
@@ -885,6 +1098,12 @@ Scope: DEV only, report-only
${report.overall.reason}
## Current DEV Layering
| Layer | Status | Evidence level | Current conclusion | Required next proof |
| --- | --- | --- | --- | --- |
${layeringLines}
## Milestones
| Milestone | Status | Highest visible level | Live evidence | Summary |