152 lines
6.8 KiB
JavaScript
152 lines
6.8 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
|
|
const ACTIONS = new Set(["DRAFT", "CONFIRM_LANGUAGE", "CHECK_DISPATCH", "DISPATCH", "REPORT_DELIVERY", "TARGET_ACCEPT", "VERIFY_EFFECT", "CORRECT", "REJECT"]);
|
|
const STATES = new Set(["DRAFTED", "LANGUAGE_CONFIRMED", "DISPATCH_ELIGIBLE", "DISPATCHED", "DELIVERED", "TARGET_ACCEPTED", "REALITY_VERIFIED", "SUPERSEDED", "REJECTED"]);
|
|
const SOURCES = new Set(["HUMAN_DIRECT_LANGUAGE", "PERSONA_COMMIT", "MODEL_RESPONSE", "REALITY_EVIDENCE"]);
|
|
const CLAIMS = new Set(["LANGUAGE_ONTOLOGY", "LANGUAGE_SIMULATION", "ENGINEERING_PROPOSAL", "REALITY_CLAIM"]);
|
|
|
|
function required(object, field) {
|
|
if (typeof object[field] !== "string" || object[field].trim() === "") throw new TypeError(`${field} must be a non-empty string`);
|
|
}
|
|
|
|
function authorized(value) {
|
|
return Boolean(value?.current && value?.scoped && value?.unexpired && typeof value.ref === "string" && value.ref.length > 0);
|
|
}
|
|
|
|
function proofFor(evidence, target, proof) {
|
|
return (evidence ?? []).some((item) => item?.external === true && item?.verified === true && item?.target === target && Array.isArray(item.proves) && item.proves.includes(proof));
|
|
}
|
|
|
|
function idFor(value) {
|
|
return `GH-BR-${createHash("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 20)}`;
|
|
}
|
|
|
|
export function compileBroadcast(event) {
|
|
if (!event || typeof event !== "object" || Array.isArray(event)) throw new TypeError("event must be an object");
|
|
for (const field of ["broadcast_id", "action", "current_state", "issuer", "source_layer", "channel_id", "purpose", "claim_layer", "payload_ref", "payload_digest", "requested_effect"]) required(event, field);
|
|
if (!ACTIONS.has(event.action)) throw new TypeError("unsupported action");
|
|
if (!STATES.has(event.current_state)) throw new TypeError("unsupported current_state");
|
|
if (!SOURCES.has(event.source_layer)) throw new TypeError("unsupported source_layer");
|
|
if (!CLAIMS.has(event.claim_layer)) throw new TypeError("unsupported claim_layer");
|
|
if (!Array.isArray(event.audience) || event.audience.length === 0 || event.audience.some((value) => typeof value !== "string" || value.length === 0)) throw new TypeError("audience must contain target ids");
|
|
|
|
let next = event.current_state;
|
|
let result = "NO_EXTERNAL_EFFECT";
|
|
let nextStep = "NONE";
|
|
const boundaries = [];
|
|
const evidence = Array.isArray(event.evidence) ? event.evidence : [];
|
|
const directIssuer = event.source_layer === "HUMAN_DIRECT_LANGUAGE" || event.source_layer === "PERSONA_COMMIT";
|
|
|
|
if (event.action === "DRAFT") {
|
|
next = "DRAFTED";
|
|
result = "LANGUAGE_DRAFT_ONLY";
|
|
nextStep = "ISSUER_REVIEW";
|
|
boundaries.push("DRAFT_IS_NOT_BROADCAST");
|
|
}
|
|
if (event.action === "CONFIRM_LANGUAGE") {
|
|
if (!directIssuer) {
|
|
next = "REJECTED";
|
|
nextStep = "REQUIRE_DIRECT_ISSUER_CONFIRMATION";
|
|
} else {
|
|
next = "LANGUAGE_CONFIRMED";
|
|
result = "LANGUAGE_STATE_ONLY";
|
|
nextStep = "CHECK_DISPATCH_AUTHORIZATION";
|
|
}
|
|
boundaries.push("LANGUAGE_CONFIRMATION_IS_NOT_DISPATCH");
|
|
}
|
|
if (event.action === "CHECK_DISPATCH") {
|
|
if (event.current_state !== "LANGUAGE_CONFIRMED" || !authorized(event.authorization)) {
|
|
next = event.current_state;
|
|
result = "PENDING_AUTHORIZATION";
|
|
nextStep = "OBTAIN_CURRENT_SCOPED_DISPATCH_AUTHORIZATION";
|
|
} else {
|
|
next = "DISPATCH_ELIGIBLE";
|
|
result = "DISPATCH_ELIGIBLE_NOT_SENT";
|
|
nextStep = "SEND_THROUGH_AUTHORIZED_ADAPTER";
|
|
}
|
|
}
|
|
if (event.action === "DISPATCH") {
|
|
const sent = event.audience.every((target) => proofFor(evidence, target, "DISPATCHED_TO_TARGET_ROUTE"));
|
|
if (event.current_state !== "DISPATCH_ELIGIBLE" || !authorized(event.authorization) || !sent) {
|
|
next = event.current_state;
|
|
result = "NO_VERIFIED_DISPATCH";
|
|
nextStep = "CAPTURE_PER_TARGET_DISPATCH_RECEIPT";
|
|
} else {
|
|
next = "DISPATCHED";
|
|
result = "DISPATCH_VERIFIED_ONLY";
|
|
nextStep = "WAIT_FOR_PER_TARGET_DELIVERY";
|
|
}
|
|
boundaries.push("DISPATCH_IS_NOT_DELIVERY");
|
|
}
|
|
if (event.action === "REPORT_DELIVERY") {
|
|
const delivered = event.audience.every((target) => proofFor(evidence, target, "DELIVERED_TO_TARGET"));
|
|
if (!delivered) {
|
|
result = "DELIVERY_UNVERIFIED";
|
|
nextStep = "CAPTURE_PER_TARGET_DELIVERY_RECEIPT";
|
|
} else {
|
|
next = "DELIVERED";
|
|
result = "DELIVERY_VERIFIED_ONLY";
|
|
nextStep = "WAIT_FOR_INDEPENDENT_TARGET_ACCEPTANCE_IF_REQUIRED";
|
|
}
|
|
boundaries.push("DELIVERY_IS_NOT_TARGET_ACCEPTANCE");
|
|
}
|
|
if (event.action === "TARGET_ACCEPT") {
|
|
const accepted = event.audience.every((target) => proofFor(evidence, target, "TARGET_ACCEPTED"));
|
|
if (!accepted) {
|
|
result = "TARGET_ACCEPTANCE_UNVERIFIED";
|
|
nextStep = "OBTAIN_INDEPENDENT_TARGET_ACCEPTANCE";
|
|
} else {
|
|
next = "TARGET_ACCEPTED";
|
|
result = "TARGET_ACCEPTANCE_RECORDED";
|
|
nextStep = "VERIFY_REQUESTED_EFFECT_SEPARATELY";
|
|
}
|
|
boundaries.push("TARGET_ACCEPTANCE_IS_NOT_REALITY_EFFECT");
|
|
}
|
|
if (event.action === "VERIFY_EFFECT") {
|
|
const verified = event.audience.every((target) => proofFor(evidence, target, event.requested_effect));
|
|
if (!verified || event.claim_layer !== "REALITY_CLAIM") {
|
|
result = "REQUESTED_EFFECT_UNVERIFIED";
|
|
nextStep = "PROVIDE_SCOPED_EXTERNAL_EFFECT_RECEIPTS";
|
|
} else {
|
|
next = "REALITY_VERIFIED";
|
|
result = "REQUESTED_EFFECT_VERIFIED";
|
|
nextStep = "CLOSE_WITH_SCOPED_READBACK";
|
|
}
|
|
}
|
|
if (event.action === "CORRECT") {
|
|
if (typeof event.supersedes !== "string" || event.supersedes.length === 0) {
|
|
result = "CORRECTION_PENDING_ADDRESSABLE_TARGET";
|
|
nextStep = "NAME_PRIOR_BROADCAST_ID";
|
|
} else {
|
|
next = "SUPERSEDED";
|
|
result = "PRIOR_BROADCAST_SUPERSEDED_IN_LANGUAGE_RECORD";
|
|
nextStep = "ISSUE_NEW_DRAFT_AND_RETEST";
|
|
}
|
|
}
|
|
if (event.action === "REJECT") {
|
|
next = "REJECTED";
|
|
result = "BROADCAST_REJECTED";
|
|
}
|
|
if (event.source_layer === "MODEL_RESPONSE") boundaries.push("MODEL_RESPONSE_IS_NOT_BROADCAST_EVIDENCE");
|
|
if (event.claim_layer === "LANGUAGE_SIMULATION") boundaries.push("SIMULATION_CANNOT_VERIFY_EXTERNAL_EFFECT");
|
|
boundaries.push("BROADCAST_DOES_NOT_GRANT_IDENTITY_RELATIONSHIP_OR_AUTHORITY");
|
|
|
|
const receipt = {
|
|
schema: "guanghu.broadcast-receipt/v1",
|
|
contract_id: "GH-BROADCAST-0001",
|
|
broadcast_id: event.broadcast_id,
|
|
issuer: event.issuer,
|
|
channel_id: event.channel_id,
|
|
audience: [...event.audience],
|
|
purpose: event.purpose,
|
|
payload: { ref: event.payload_ref, digest: event.payload_digest },
|
|
requested_effect: event.requested_effect,
|
|
state: { before: event.current_state, after: next },
|
|
result,
|
|
evidence,
|
|
boundaries: [...new Set(boundaries)],
|
|
supersedes: event.action === "CORRECT" && event.supersedes ? [event.supersedes] : [],
|
|
next_step: nextStep,
|
|
};
|
|
return { ...receipt, receipt_id: idFor(receipt) };
|
|
}
|