cortexdb-client 0.2.0

Typed gRPC client for CortexDB (AI memory + knowledge graph sidecar)
Documentation
syntax = "proto3";
package cortexdb.v1;
option go_package = "github.com/liliang-cn/cortexdb/v2/pkg/rpc/v1;rpcv1";

// The decision ledger, over the wire.
//
// contract.proto reads how well established a *fact* is. This says why an
// *action* was taken: which facts it rested on, who took it, what it replaced,
// and what else was decided the same way. The two belong together — a chain of
// premises without their grades looks like evidence and is not — which is why
// every premise here carries the contract's grade and source.
//
// Its own file rather than messages on graph.proto for contract.proto's
// reason. A decision is stored as a graph record today, which is what makes a
// chain a graph walk and puts the ledger in every existing view for free; but
// that is an implementation fact, and putting these RPCs in
// KnowledgeGraphService would pin it into the name a client calls forever.

// DecisionPremise is one thing a decision rested on, with how sure that thing
// was.
message DecisionPremise {
  // id is the node id or edge id the decision named.
  string id = 1;
  // edge says the premise is a fact — a relation — rather than a thing. It
  // matters to a reader: a graph's assertions are mostly edges, and a client
  // that renders only the nodes drops the half a decision usually stood on.
  bool edge = 2;
  // type is node_type or edge_type.
  string type = 3;
  // content is a node's label; edges have none.
  string content = 4;
  // from and to are a fact's ends, empty on a node.
  string from = 5;
  string to = 6;
  // decision says this premise is itself a decision, which is what makes a
  // chain recurse.
  bool decision = 7;
  // grade and source are the premise's own contract keys. Empty means the
  // record carries none, which is an answer and a different one from
  // "asserted".
  string grade = 8;
  string source = 9;
  // missing says the premise was recorded and has since been deleted. It
  // cannot happen at write time — recording refuses an unknown premise — so it
  // means the shelf changed under a decision that already stands, which the
  // reader has to be told rather than shown a gap.
  bool missing = 10;
}

// Decision is one ledger entry.
message Decision {
  string id = 1;
  // kind is the shape of the decision: load, review, action, assert, or a word
  // of the caller's own. The vocabulary is open — precedents groups by
  // whatever is written — and those four are what the product uses.
  string kind = 2;
  string actor = 3;
  // at is RFC 3339, as written. A string rather than a Timestamp for the
  // reason GradedRecord.at is one: the store keeps what the producer stamped,
  // and a parse here would turn one malformed record into a failed read of the
  // whole list.
  string at = 4;
  // verdict is the outcome in the actor's own word — hold, ship, rejected —
  // and is never interpreted across actors, for the reason state is not.
  string verdict = 5;
  // subject is the node id the decision was about.
  string subject = 6;
  // note is the decision in words.
  string note = 7;

  string grade = 8;
  string source = 9;
  string producer = 10;
  string state = 11;
  string why = 12;

  repeated DecisionPremise premises = 13;
  // supersedes is what this decision replaced. Repeated rather than a single
  // id because a decision consolidating three earlier ones is ordinary, and a
  // field that could only hold one would make the ledger lie by arithmetic.
  repeated string supersedes = 14;
}

// RecordDecisionRequest writes why something was done.
message RecordDecisionRequest {
  // id names the decision. Empty mints one. Given, it makes the write
  // idempotent, which is what lets a caller replay a transcript without
  // doubling its ledger.
  string id = 1;
  string kind = 2;
  // actor is required: a decision nobody made is a note.
  string actor = 3;
  // note is required, for the reason a refused record needs a why — a ledger
  // entry a reader cannot act on is noise.
  string note = 4;
  string verdict = 5;
  // subject must be a node that exists.
  string subject = 6;
  // premises are node ids and edge ids the decision rested on. Every one must
  // exist: a decision resting on a fact that does not exist is not a decision,
  // and accepting it would produce a chain that reads as evidence while
  // pointing at nothing. The whole request is refused and nothing is written.
  repeated string premises = 7;
  // supersedes must exist and must be a decision.
  string supersedes = 8;
  // at is RFC 3339. Empty means now.
  string at = 9;

  // The contract keys a caller may override. The defaults are the case the
  // ledger exists for — a named person signing a decision, which is
  // established outside any producer and so is verified — and an agent
  // recording its own decision says so by setting producer and grade.
  string source = 10;
  string producer = 11;
  string grade = 12;
  string state = 13;
  // why is required by the contract when grade is held or refused.
  string why = 14;
}

message RecordDecisionResponse {
  Decision decision = 1;
}

// DecisionChainRequest asks why one decision was made.
message DecisionChainRequest {
  // id, with or without the "decision:" prefix.
  string id = 1;
  // max_depth is how many decision hops to follow. 0 takes the server's
  // default; the server also caps it, because a chain is a graph walk and a
  // graph is not a tree.
  int32 max_depth = 2;
}

// DecisionChainResponse is a decision and everything it stands on.
message DecisionChainResponse {
  string root = 1;
  // decisions is the root first, then every decision reachable through
  // supersedes and through premises that are themselves decisions, breadth
  // first — so a truncated chain is truncated at the far end.
  repeated Decision decisions = 2;
  int32 depth = 3;
  // truncated says the depth bound stopped the walk with decisions still
  // unvisited. A chain that quietly stopped reads as a complete account of why
  // something was done, which is the one thing it must never do.
  bool truncated = 4;
}

// PrecedentsRequest asks what was decided this way before. Both kind and
// subject empty is refused rather than meaning "the whole ledger": a caller
// asking for every decision anybody ever made is not asking about a precedent,
// and on a shared brain that is other people's ledger.
message PrecedentsRequest {
  string kind = 1;
  string subject = 2;
  // exclude leaves one decision out — the one being decided now is not its own
  // precedent.
  string exclude = 3;
  // limit caps the rows. 0 takes the server's default.
  int32 limit = 4;
}

message PrecedentsResponse {
  // decisions are newest first.
  repeated Decision decisions = 1;
  int32 count = 2;
  // truncated says the limit cut the list short, so "3 precedents" is never
  // mistaken for "only 3 precedents".
  bool truncated = 3;
}

// DecisionService records and reads the ledger. RecordDecision is the only
// write, and it is a write in the ordinary sense — it puts a node and its
// edges on the same shelf every other producer writes to, graded by the same
// contract, so contract_tally counts a decision without being told about
// decisions.
service DecisionService {
  // RecordDecision writes a decision and the edges that explain it. It fails
  // closed and it fails before writing anything: an unknown premise, an empty
  // actor or metadata the knowledge contract refuses leaves the store
  // untouched, because a decision that half-wrote has fewer premises than its
  // author believes and nothing downstream can tell that from a decision that
  // genuinely rested on less.
  rpc RecordDecision(RecordDecisionRequest) returns (RecordDecisionResponse);
  // DecisionChain walks back from a decision to what it rested on.
  rpc DecisionChain(DecisionChainRequest) returns (DecisionChainResponse);
  // Precedents lists earlier decisions of the same kind or about the same
  // subject, newest first.
  rpc Precedents(PrecedentsRequest) returns (PrecedentsResponse);
}