@xemahq/capability-projection
v0.1.1
Published
Xema OS capability projection framework. CapabilityProjector is the shared reconcile engine every capability producer drives: serialized reconciles, content-aware fingerprint short-circuit, idempotent register-then-prune scoped to the refs a source previo
Downloads
3,567
Readme
@xemahq/capability-projection
This package belongs to Layer 1 — an SDK that depends only on Layer-0
contracts (@xemahq/kernel-contracts) plus npm libraries. It owns the shared
reconcile engine behind capability projection: deriving capabilities from
metadata a producer already has, instead of hand-authoring one descriptor at a
time.
What it is
Two things, and nothing else:
CapabilitySource— the single interface a producer implements. It answers one question, "which capabilities should exist right now?", and has no other responsibility.CapabilityProjector— the engine that turns that answer into a converged registry: serialized reconciles, content-aware fingerprint short-circuit, idempotent register-then-prune, and loud-and-retry error handling.
CapabilityRegistryProjectionClient is the shipped
CapabilityProjectionSink — a registry-resolved, service-bearer-authenticated
client for capability-registry-api. The sink is a port, so tests drive an
in-memory double and the engine stays transport-free.
The projected shape (ProjectedCapability, CapabilityInvocationBinding) is a
Layer-0 contract and lives in @xemahq/kernel-contracts/capability-projection —
it crosses service boundaries, so it belongs with the protocol, not with the
engine.
Invariants
- Reconciles are serialized. Boot, post-sync and interval triggers queue on one chain; a register can never interleave with another pass's prune.
- An unchanged fingerprint short-circuits. The fingerprint hashes target content, not just the ref set, so an edited descriptor is never silently elided while the steady-state tick still costs zero writes.
- A projector prunes only refs it previously projected, and only those that no source currently claims. Two projectors share no state; two sources on one projector are differenced against the union, so neither can prune the other.
- A failed reconcile retries the whole set.
lastProjectedRefsand the fingerprint advance only after a fully successful pass, so a partial write is never mistaken for the new steady state. - Two sources emitting the same
CapabilityRefis a fail-fast error naming bothsourceKeys. Never last-writer-wins. - Provenance must name the emitting source. A target whose
provenance.sourceKeydisagrees with its source, or whose map key disagrees with its ownref, is rejected rather than absorbed.
Usage
class MySource implements CapabilitySource {
readonly sourceKey = 'my-service:my-producer';
async collectTargets(): Promise<Map<CapabilityRef, ProjectedCapability>> {
/* derive from metadata you already have */
}
}
const projector = new CapabilityProjector({
label: 'my producer',
sink: capabilityRegistryProjectionClient,
logger: new Logger('MyProjector'),
sources: [new MySource()],
});
await projector.bootReconcile(); // best-effort at boot
await projector.tickReconcile(); // on an interval; converges after an outageLicense
Apache-2.0
