Standalone per-card browser model/security/view modules for HUX-01..10 plus node+pytest suites that read the hux.v1 contract schemas directly. Reconciled drift found on integration: the activity model now accepts all 32 hux.event.v1 kinds (delegation.*, memory.suppressed, memory.retrieval_removed, budget.exhausted, side_effect.*), the autonomy model carries the external_side_effect capability, and the foundation boundary test now asserts the shipped static HUX surface exists on disk and that images never bake activated HUX_FLAGS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
/**
|
|
* Same-origin endpoint descriptions for a future HUX-02 backend adapter.
|
|
* The server must derive identity from the authenticated session, compare it
|
|
* with each request's expectedIdentity, and echo it in list responses. A
|
|
* revision appends a proposed ledger entry; forget purges content while
|
|
* retaining audit metadata. These descriptors never perform a request.
|
|
*/
|
|
|
|
import { memoryControlEnabled } from "./model.ts";
|
|
import { isOpaqueMemoryId, normalizeIdentity } from "./security.ts";
|
|
import type {
|
|
HuxIdentity,
|
|
MemoryAction,
|
|
MemoryEndpoint,
|
|
MemoryEndpointContract,
|
|
} from "./types.ts";
|
|
|
|
interface FoundationClient {
|
|
apiVersion: string;
|
|
identity: HuxIdentity;
|
|
endpoint(path: string): string;
|
|
}
|
|
|
|
function endpoint(
|
|
method: MemoryEndpoint["method"],
|
|
path: string,
|
|
responseSchema: string,
|
|
): MemoryEndpoint {
|
|
return Object.freeze({ method, path, responseSchema });
|
|
}
|
|
|
|
/**
|
|
* Describe, but do not call, the backend interface. Returning null while any
|
|
* dependency flag is absent keeps HUX-02 inert and default-off.
|
|
*/
|
|
export function createMemoryEndpointContract(
|
|
client: FoundationClient,
|
|
flags?: Iterable<string>,
|
|
): MemoryEndpointContract | null {
|
|
if (!memoryControlEnabled(flags)) return null;
|
|
if (client.apiVersion !== "hux.v1") throw new TypeError("HUX v1 client required");
|
|
const identity = Object.freeze({ ...normalizeIdentity(client.identity) });
|
|
|
|
function itemPath(memoryId: string): string {
|
|
if (!isOpaqueMemoryId(memoryId)) throw new TypeError("Opaque memory id required");
|
|
return client.endpoint(`/memories/${memoryId}`);
|
|
}
|
|
|
|
return Object.freeze({
|
|
identity,
|
|
list: endpoint("GET", client.endpoint("/memories"), "hux.memory_page.v1"),
|
|
suggestOnly: endpoint(
|
|
"PUT",
|
|
client.endpoint("/memory-settings/suggest-only"),
|
|
"hux.memory_settings.v1",
|
|
),
|
|
doNotRemember: endpoint(
|
|
"POST",
|
|
client.endpoint("/memory-blocks"),
|
|
"hux.memory_block.v1",
|
|
),
|
|
action(memoryId: string, action: MemoryAction) {
|
|
if (!["approve", "reject", "forget"].includes(action))
|
|
throw new TypeError("Unsupported memory action");
|
|
return endpoint(
|
|
"POST",
|
|
`${itemPath(memoryId)}/${action}`,
|
|
"hux.memory.v1",
|
|
);
|
|
},
|
|
revise(memoryId: string) {
|
|
return endpoint(
|
|
"POST",
|
|
`${itemPath(memoryId)}/revisions`,
|
|
"hux.memory.v1",
|
|
);
|
|
},
|
|
});
|
|
}
|