Hive-Knowledge Graph Contract
What the chain emits, and how downstream consumers project & filter it.
The chain is the single durable input to the Hive-Knowledge Graph
(impactium-query-layer.md). Every state-changing Msg emits events sufficient
for imp-ledger's indexer to build graph nodes/edges without re-executing
the state machine (ARCHITECTURE.md invariant #4). This file is the contract
imp-ledger and imp-wallet implement against.
Consumers regenerate typed clients from proto/ via buf generate — one
command yields Rust (sdk/proto) and TypeScript (proto/gen/ts). Never
hand-write protocol code.
Filters every consumer must support
| Filter | Values | Source field |
|---|---|---|
verification_tier |
SELF_LOGGED | NOTARIZED |
common.v1.VerificationTier on Capsule/MintRecord/mint.claim_resolved |
scope |
INWARD | OUTWARD |
common.v1.Scope on claims, personal logs, capsules, mint records, truecost records |
- Self-logged impact is visible by default, labeled, never hidden — the UI distinguishes it from notarized, but does not suppress it.
- The ledger's inward | outward feed toggle is the
scopefilter; the wallet's personal-ledger view uses it to look "inward" (impact on self) vs "outward" (impact on society).
Events → graph (indexer mapping)
| Event kind | Node/edge to build |
|---|---|
identity.entity_registered |
Entity node (class, lineage, pubkey → current_pubkey; later rotations replace the current binding) |
identity.product_registered |
Product node (product_id, governed class key, hex-encoded pubkey, owner_entity_id) + CREATED edge (Entity→Product) |
spore.spawned |
SPAWNED edge (parent→child), partition root — carries class (HUMAN or ORGANIZATION org wallets, §18) |
spore.spawn_rate_accounted |
merge the referrer's current bounded window, count, limit, and parameter version onto its Entity node so approaching the governed cap is public |
org.registered |
merge legal registration fields onto the organization Entity node |
org.member_added / org.member_role_set / org.member_removed |
upsert MEMBER_OF edge (member→organization) with role and active state |
org.formation_proposed |
Formation node (proposer, required partners, terms-document ref, proposed legal name) + PROPOSED edge (proposer→Formation) + FORMATION_PARTNER edges (Formation→each required partner) |
org.formation_accepted |
ACCEPTED_FORMATION edge (accepting partner→Formation) — one durable edge per acceptance; remaining partners are derived from required-minus-accepted, never stored as a mutable list |
org.formation_completed |
merge Formation completed=true + link the created organization Entity — the formation record stays permanent |
org.partner_linked |
PARTNER_OF edge (founding partner→formed organization) |
bliss.job_enqueued |
PipelineJob node (job_id, kind, payload_ref, enqueued_at_height, run_at_height, status=PENDING) + ENQUEUED edge (actor Entity→PipelineJob) — the wallet queries jobs by their enqueuing actor |
bliss.job_processed |
merge PipelineJob status=DONE + processed height |
bliss.job_failed |
merge PipelineJob status=FAILED + reason + height — the failed job is retained, never dropped |
document.created |
Document node owned by an Entity |
document.version_added |
DocumentVersion node with the full content manifest + SUPERSEDES edge to its parent layer |
document.version_signed |
SIGNED edge (signer Entity→DocumentVersion); version remains pending until all required signers land |
document.version_effective |
merge DocumentVersion status=EFFECTIVE and effective height |
document.version_deprecated |
merge DocumentVersion deprecated=true + reason — the layer remains permanent |
upgrade.scheduled |
UpgradePlan node carrying halt height + certified node-bundle content root |
upgrade.canceled |
merge cancellation flag/reason onto UpgradePlan — never delete the plan |
upgrade.applied |
UpgradeMigration node recording module, from/to consensus versions, binary name, and height |
mint.claim_submitted |
Claim node (pending) carrying ordered per-domain disclosure, 32-byte evidence anchor, and versioned anchor scheme; legacy claims may omit these additive fields |
mint.claim_resolved |
Capsule node (MINTED edge) or failed-claim node — carries verification_tier + scope; evidence_hash is an opaque commitment whose scheme is declared in anchor_scheme (SHA256-V1 or SALTED-SHA256-V1, §26) — read the scheme, never assume it. A bare SHA256-V1 anchor over a low-entropy plaintext is recoverable by enumeration, which is precisely what the salted scheme exists to prevent |
domain.policy_applied |
append/version an ImpactDomain policy node (name, disclosure, recoverability default, domain_policy_version); genesis v1 and every governed change remain queryable |
domain.policy_proposed / domain.vote_cast |
append the public governance proposal/vote record for an ImpactDomain add or policy change |
domain.openness_bonus_proposed / domain.openness_bonus_vote_cast |
append the public governance proposal/vote record for MAX_OPENNESS_BONUS |
domain.openness_bonus_applied |
append the governed maximum in millis and its openness_param_version; genesis v1 is 250 millis |
mint.claim_resolved domain fields |
Capsule/MintRecord carries the complete impact_domains set, per-domain disclosure/anchor/scheme data, and the domain_policy_version in force; existence and NET remain public regardless of policy. Openness bonus is computed at 0LOOKUP, never folded into mint-time bonus_millis — but it is absolute, identical for every viewer (§28). Only the upstream_coi_bonus component is perspectival. |
Identity bindings use the public key, not a hash-derived guess at the identity ID.
identity.entity_registered.pubkey and identity.product_registered.pubkey
are hex-encoded public keys bound to the event's assigned Entity or Product ID.
Product class is the classification registry key, such as agent, rather
than an implementation-specific debug representation. A Product's owner is
the Entity named by owner_entity_id.
Entity key rotation emits identity.key_rotated with entity_id, old_pubkey
and new_pubkey; consumers replace the Entity's current binding and stop
resolving the old key. Product key rotation is not currently implemented.
Historical Product events that omit pubkey do not establish a key binding;
replaying them must leave that binding unknown rather than inventing one.
x/domain retains MAX_OPENNESS_BONUS under a versioned history key as well as
the current pointer. Karma projects the applied history and exposes
capsuleLookup(id, lookupParty): the public record plus a reusable bounded walk
tree, a Scope-Matrix pure-folded from that tree, and a fixed-point valuation stamp (base, upstream-COI and absolute
openness components in millis, their additive zeroBonusMillis, exact
valueImpMillis, committed parameter version, graph height, minute-bucket
timestamp, truncation, and v0 flags). A sealed path remains in the walk with
its public Total and meta=SEALED; it never leaks children. Scope-Matrix cells
are deterministically ordered by depth then scope_dir then domain and report
traversed/sealed counts, reached Total, and an explicit depth-cap flag. The valuation is
derived per lookup and is never stored on the Capsule. impactStamp is the
STAMP-SIERPINSKI-V1 pure SVG projection of the same walk and carries its
canonical integer encoding, fractal type, and flags. Alignment is the primary
hue channel; while alignment inputs remain unwired, neutral hue is explicitly
flagged ALIGNMENT_HUE_RESERVED_V0. Domain is a secondary texture. Sealed
boundaries render as opaque grey sub-triangles without gated texture/Meta.
| mint.downline_share | DOWNLINE_SHARE edge (minter→ancestor) — NOTARIZED only |
| mint.genesis_residual | GENESIS_RESIDUAL edge (mint→founder) — NOTARIZED only |
| weights.proposed | WeightProposal node |
| weights.vote_cast | VOTED edge (voter→proposal), proximity weight |
| weights.applied | WeightEntry node/version bump (matrix_version) |
| truecost.delivered | TrueCost node + DELIVERED edge; resource_legs as properties |
| truecost.split | COST_SHARE edge (record→beneficiary); traded flag |
| identity.node_updated | merge onto the Entity node (mutable @Node attrs; provenance stays registration) |
| identity.key_rotated | merge onto the Entity node (current_pubkey, key_rotations+1) — the identity survives the key (decisions §18) |
| identity.keyholders_set | append a KeyholderSet version and link its designated Keyholder Entities to the subject |
| identity.recovery_proposed | append a public RecoveryRequest node with subject, requested key, set version, proposer, threshold progress, and Substrate-verification status |
| identity.recovery_approved | append/idempotently merge a distinct Keyholder approval and public n-of-3 progress |
| identity.recovery_executed | mark the request executed and link it to the resulting identity.key_rotated event |
| identity.recovery_cancelled / identity.recovery_invalidated | mark the append-only request terminal with height and public reason; never delete it |
| constitution.article_proposed | Article node (stage=MUSE, title, proposer) |
| constitution.vote_cast | VOTED edge (voter→Article), target_stage |
| constitution.stage_advanced | merge Article stage = to + ADVANCED edge (actor→Article: from, to, rationale) — the deliberation record |
| constitution.article_ratified | merge Article stage=HARDENED, ratified=true |
| resource.release_published | Release node (keyed product:version, carrying the FULL manifest: artifact, sizes, chunk hashes, content root) + RELEASED edge (Product→Release) — the resource tier serves bytes against this |
| resource.certified | CERTIFIED edge (certifier Entity→Product) — root-gated pre-genesis, I-corps later (decisions §15) |
| resource.release_deprecated | merge Release deprecated=true + reason — flagged, never removed (permanence) |
notary.sealed and validators.updated are infrastructure, not graph facts —
the projection ignores them (the seal/schema registry replays with the chain).
Partition root resolution
Only identity.entity_registered / spore.spawned carry root_id on the wire.
Every other fact's partition root is its acting entity's root — the wallet's
COA root is its partition key (spore §). Because an entity is always
registered (carrying root_id) before it acts, the actor's root is already in
the graph; the indexer resolves it from the acting entity (a same-block overlay
covers register-then-act within one block). An unresolved root (a malformed /
out-of-order stream) never drops the fact — permanence — it lands with an empty
root and MAPPED mapping-confidence to flag the inference. (Implemented in
imp-ledger / Karma transform.rs.)
Claim lifecycle & failed claims
mint.claim_resolved merges onto the existing Claim node: status →
minted | failed. A failed claim is kept as a first-class, queryable node
(the "failed-claim node") — never deleted or hidden — so a member's history
shows rejected claims beside minted capsules. A minted resolution additionally
creates the Capsule node + MINTED edge.
Governance-input note
Weight-Matrix votes are weighted by proximity to subject matter, and the
leading proximity function is graph-derived (lineage distance + participation
edges to the subject node type). That makes the graph a governance input,
not only a read surface: proximity queries must be deterministic, versioned,
and provable (ICS23) like everything else the chain commits to. The on-chain
x/actioncatalog proximity function is a v0 placeholder (override table); the
graph-derived version is the standing balance workstream.
Determinism / provenance
Every node/edge carries the four provenance properties (root, blockHash,
txHash, schemaVersion). The projection's schemaVersion bumps whenever the
ontology grows (a node/edge kind is added), so a consumer can tell which shape a
record was written under and the graph can be rebuilt by replay at any version. Mint records additionally carry
action_catalog_version — the ActionCatalog version in force at mint time —
so historical impact figures never change when weights are revised.