1/**
2 * Sealed Transport Core
3 *
4 * One function. One check. Propagation calls isSealed() before each hop.
5 * If sealed, intermediary nodes get a redacted payload. They see a
6 * pass-through record in .flow but cannot see the content. The destination
7 * (leaf node with no cascade-enabled children) gets the full payload.
8 */
9
10/**
11 * Determine if a signal should be delivered in sealed mode.
12 *
13 * Sealed if:
14 * - The originating node's cascadeConfig.mode === "sealed"
15 * - OR the payload itself carries _sealed: true
16 *
17 * @param {object} cascadeConfig - the source node's metadata.cascade
18 * @param {object} payload - the signal payload
19 * @returns {boolean}
20 */
21export function isSealed(cascadeConfig, payload) {
22 if (cascadeConfig?.mode === "sealed") return true;
23 if (payload?._sealed === true) return true;
24 return false;
25}
26
27/**
28 * Redact a payload for intermediary hops.
29 * Preserves routing metadata (tags, signalId, source) but strips content.
30 * The intermediary sees that a sealed signal passed through. Nothing more.
31 *
32 * @param {object} payload - the full payload
33 * @returns {object} redacted payload for intermediary delivery
34 */
35export function sealPayload(payload) {
36 return {
37 _sealed: true,
38 _passthrough: true,
39 tags: payload?.tags || [],
40 };
41}
42
1import { isSealed, sealPayload } from "./core.js";
2
3export async function init(core) {
4 const { default: router, setMetadata } = await import("./routes.js");
5 setMetadata(core.metadata);
6
7 return {
8 router,
9 exports: {
10 isSealed,
11 sealPayload,
12 },
13 };
14}
15
1export default {
2 name: "sealed-transport",
3 version: "1.0.1",
4 builtFor: "treeos-cascade",
5 description:
6 "Handles the pass-through mode for signals that should arrive unchanged. When a cascade " +
7 "signal has its mode set to sealed in its metadata.cascade configuration or when the signal " +
8 "itself carries a sealed flag, propagation calls into sealed transport instead of normal " +
9 "delivery. Normal delivery lets extensions inject context at each intermediary node. Sealed " +
10 "delivery skips that at intermediary nodes. The signal passes through untouched. Intermediary " +
11 "nodes can see in .flow that something passed through them. They cannot see the payload. They " +
12 "can still gate or block at their extension scope level because that is a kernel behavior, not " +
13 "an enrichment behavior. At the destination node, sealed transport unwraps and delivers " +
14 "normally. The AI sees the full payload. The signal survived the path intact. Important for " +
15 "cross-land communication where intermediary trees should not modify in-transit data. Also " +
16 "important for private conversations between two specific nodes where the path between them " +
17 "passes through shared tree space. Exports a deliveryMode function that propagation checks. " +
18 "If sealed, propagation skips enrichment at intermediary hops. One function. One check.",
19
20 needs: {
21 models: [],
22 extensions: ["propagation"],
23 },
24
25 optional: {},
26
27 provides: {
28 models: {},
29 routes: "./routes.js",
30 tools: false,
31 jobs: false,
32 orchestrator: false,
33 energyActions: {},
34 sessionTypes: {},
35 env: [],
36 cli: [
37 {
38 command: "seal [action]", scope: ["tree"],
39 description: "Sealed transport. No action shows seal status. Actions: on, off.",
40 method: "GET",
41 endpoint: "/node/:nodeId/seal",
42 subcommands: {
43 "on": {
44 method: "POST",
45 endpoint: "/node/:nodeId/seal/on",
46 description: "Set cascade mode to sealed at this position",
47 },
48 "off": {
49 method: "POST",
50 endpoint: "/node/:nodeId/seal/off",
51 description: "Set cascade mode to open",
52 },
53 },
54 },
55 ],
56
57 hooks: {
58 fires: [],
59 listens: [],
60 },
61 },
62};
63
1import express from "express";
2import authenticate from "../../seed/middleware/authenticate.js";
3import { sendOk, sendError, ERR } from "../../seed/protocol.js";
4import Node from "../../seed/models/node.js";
5
6let _metadata = null;
7export function setMetadata(m) { _metadata = m; }
8
9const router = express.Router();
10
11// GET /node/:nodeId/seal - seal status
12router.get("/node/:nodeId/seal", authenticate, async (req, res) => {
13 try {
14 const node = await Node.findById(req.params.nodeId).select("name metadata").lean();
15 if (!node) return sendError(res, 404, ERR.NODE_NOT_FOUND, "Node not found");
16 const meta = node.metadata instanceof Map ? Object.fromEntries(node.metadata) : (node.metadata || {});
17 const mode = meta.cascade?.mode || "open";
18 sendOk(res, {
19 nodeId: req.params.nodeId,
20 nodeName: node.name,
21 cascadeMode: mode,
22 sealed: mode === "sealed",
23 });
24 } catch (err) {
25 sendError(res, 500, ERR.INTERNAL, err.message);
26 }
27});
28
29// POST /node/:nodeId/seal/on - set sealed
30router.post("/node/:nodeId/seal/on", authenticate, async (req, res) => {
31 try {
32 await _metadata.batchSetExtMeta(req.params.nodeId, "cascade", { mode: "sealed" });
33 sendOk(res, { message: "Cascade mode set to sealed", mode: "sealed" });
34 } catch (err) {
35 sendError(res, 500, ERR.INTERNAL, err.message);
36 }
37});
38
39// POST /node/:nodeId/seal/off - set open
40router.post("/node/:nodeId/seal/off", authenticate, async (req, res) => {
41 try {
42 await _metadata.batchSetExtMeta(req.params.nodeId, "cascade", { mode: "open" });
43 sendOk(res, { message: "Cascade mode set to open", mode: "open" });
44 } catch (err) {
45 sendError(res, 500, ERR.INTERNAL, err.message);
46 }
47});
48
49export default router;
50
Loading comments...