package main // A record that needs the operator (novox/hq ADR 0290 rule 4, to-be 55 §5): once the knowledge base's own review // approves it, the operator is asked on the router with Approve and Decline, both at the level approve, so only a channel // that proves who answered can carry either (ADR 0259, as claude-code's proposals ask it, ADR 0274). Each option // binds the act it authorises: this record, this version's digest. The knowledge base accepts the record only on // the router's warrant for Approve, read back from the router's own record of the ask (which only the router // writes) and held to the ask composed again from the record: the same digest, an option it offered, at its // level, in time, and the act the option bound. A record changed after it was asked finds the digests differ, and // nothing is accepted. The warrant is kept with the record. import ( "context" "crypto/rand" "encoding/hex" "encoding/json" "fmt" "regexp" "strconv" "strings" "time" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/asks" ) // Module is this module's name: the one the bus grants its asks under. const Module = "mesh-knowledge" // The two answers, both at the level approve. const ( OptionApprove = "approve" OptionDecline = "decline" ) // AskLasts is how long the operator has to answer: a day less a margin, under the router's bound for an approval. const AskLasts = asks.ApproveLasts - 10*time.Minute // The states of an operator's ask, as the record keeps them. const ( AskWaiting = "waiting for the operator's answer" AskApproved = "approved by the operator" AskDeclined = "declined by the operator" ) // AskBus is the operator channel as this module reaches it: publish an ask under its own name, and read the // router's record of one of its asks. type AskBus interface { Publish(subject string, body any, id string) error Record(id string) (*stdio.StateEntry, error) } type sdkAskBus struct{} func (sdkAskBus) Publish(subject string, body any, id string) error { return stdio.SeatPublish(subject, body, id) } func (sdkAskBus) Record(id string) (*stdio.StateEntry, error) { return stdio.SeatRecord("", id) } // act is what an answer binds: this record's version, by its digest, and the answer. func act(r *Record, a *OperatorAsk, option string) asks.Act { return asks.Act{"verb": "knowledge-base.accept", "option": option, "ask": a.ID, "kind": r.Kind, "number": strconv.Itoa(r.Number), "version": strconv.Itoa(a.Version), "digest": r.Digest()} } var ( unshownPath = regexp.MustCompile(`[/\\@~$]|\d+\.\d+\.\d+|[A-Za-z0-9+/=_]{24,}|(?i)\b[a-z0-9-]+\.[a-z]{2,12}\b`) ) // shown is a line the operator's phone may be shown: no path, address, host-like name or long unbroken word — // narrower than the router's own rule, so the ask is not refused for its words. func shown(line string) bool { return !unshownPath.MatchString(line) } // fingerprint is a digest as the operator is shown it: its first 24 hexadecimal digits in groups of four. func fingerprint(digest string) string { h := strings.TrimPrefix(digest, "sha256:") if len(h) < 24 { return h } var g []string for i := 0; i < 24; i += 4 { g = append(g, h[i:i+4]) } return strings.Join(g, " ") } // composeAsk is the ask for a record, composed from the record and its ask alone: asked once, and composed // again to hold the warrant to it. func composeAsk(r *Record, a *OperatorAsk) asks.Ask { name := r.Key().String() headline := "Accept " + name + "?" var b strings.Builder fmt.Fprintf(&b, "%s was proposed by %s and approved by the knowledge base's own review. Its author says it needs your approval before it holds.", name, r.Author) if shown(r.Title) { fmt.Fprintf(&b, "\n\nIts title: %s.", strings.TrimSuffix(r.Title, ".")) } if len(r.Clauses) > 0 { fmt.Fprintf(&b, "\n\nIts %d clause(s):", len(r.Clauses)) size, hidden := 0, 0 for _, c := range r.Clauses { lead := c.Lead() if !shown(lead) || size+len(lead) > 1200 { hidden++ continue } size += len(lead) fmt.Fprintf(&b, "\n%d. %s", c.N, lead) } if hidden > 0 { fmt.Fprintf(&b, "\n(%d lead(s) not shown here)", hidden) } } fmt.Fprintf(&b, "\n\nRead it whole with the knowledge base's get, number %d; its fingerprint is %s.", r.Number, fingerprint(r.Digest())) out := asks.Ask{ID: a.ID, Headline: headline, Explanation: b.String(), Who: asks.Operator, Expires: a.At.Add(AskLasts), OnExpiry: "the record stays proposed; nothing of it is in force", About: "knowledge." + r.Kind + "." + strconv.Itoa(r.Number)} for _, o := range []struct{ id, label, does string }{ {OptionApprove, "Approve", "the record is accepted and its clauses are in force"}, {OptionDecline, "Decline", "the record stays proposed; nothing of it is in force"}, } { binds, _ := asks.ActDigest(act(r, a, o.id)) out.Options = append(out.Options, asks.Option{ID: o.id, Label: o.label, Does: o.does, Level: asks.Approve, Binds: binds}) } return out } func newAskID(r *Record) string { var b [4]byte _, _ = rand.Read(b[:]) return fmt.Sprintf("kb-%s-%d-%s", r.Kind, r.Number, hex.EncodeToString(b[:])) } // askOperator asks the operator to approve a record the knowledge base's review approved, and keeps the ask with // it. The caller holds the write lock. An ask that could not be made or published is taken back, and the review is // asked again after a pause, counted with the tries before it (tries): the record stays proposed, and is reviewed // at most MostReviewTries times. func (k *KB) askOperator(ctx context.Context, held *Entry, w *Record, by string, tries int) (string, error) { version := held.CurrentVersion if held.Pending != nil { version = held.PendingVersion } unasked := func(why string) (string, error) { w.Ask = nil w.Judging = failedJudging(tries+1, why, k.now()) said := fmt.Sprintf("approved by the knowledge base's review, and %s (%s", why, w.Judging.owedSays()) e, err := k.Store.Get(ctx, w.Key()) if err != nil || e == nil { return "", fmt.Errorf("%s: %s, and that could not be kept (%v)", w.Key(), said, err) } if err := k.Store.Save(ctx, Version{By: ReviewBy, At: k.now(), Why: said, Record: w, Insight: e.Pending != nil}, e.Pending == nil, false, e.Revision); err != nil { return "", fmt.Errorf("%s: %s, and that could not be kept (%v)", w.Key(), said, err) } k.emit(EventReviewed, w, ReviewBy, said, e.Versions+1) return w.Key().String() + ": " + said, nil } if k.Asks == nil { return unasked("the operator cannot be asked from here") } oa := &OperatorAsk{ID: newAskID(w), At: k.now(), Version: version, Said: AskWaiting} ask := composeAsk(w, oa) if err := ask.Check(k.now()); err != nil { return unasked(fmt.Sprintf("the ask could not be made (%v)", err)) } w.Ask = oa if err := k.Store.Save(ctx, Version{By: by, At: k.now(), Why: "reviewed: approved; the operator is asked", Record: w, Insight: held.Pending != nil}, held.Pending == nil, false, held.Revision); err != nil { return "", fmt.Errorf("%s: the review could not be kept (%v); the operator was not asked", w.Key(), err) } k.emit(EventReviewed, w, by, "approved; the operator is asked", held.Versions+1) if err := k.Asks.Publish(asks.AskSubject(Module), ask, ask.ID); err != nil { k.logf("[mesh-knowledge] the ask for %s could not be published: %v", w.Key(), err) return unasked(fmt.Sprintf("the operator could not be asked (%v)", err)) } return fmt.Sprintf("%s needs the operator: asked on a channel that proves who answers (%q). It is accepted only on the operator's Approve; until then nothing of it is in force.", w.Key(), ask.Headline), nil } // routerRecord is the router's record of one ask, as far as this module reads it. type routerRecord struct { State string `json:"state"` Ask *asks.Ask `json:"ask"` Warrant *asks.Warrant `json:"warrant"` } // Reconcile decides every record waiting for the operator whose ask the router has closed: accepted on a warrant // for Approve that holds, left proposed on Decline, an expiry or a warrant that does not hold. It answers a line // for each decision. func (k *KB) Reconcile() ([]string, error) { if k.Asks == nil { return nil, nil } ctx := context.Background() k.mu.Lock() defer k.mu.Unlock() all, err := k.Store.All(ctx) if err != nil { return nil, err } var said []string for _, e := range all { w := e.Working() if w.Status != StatusProposed || w.Ask == nil || w.Ask.Said != AskWaiting { continue } entry, err := k.Asks.Record(w.Ask.ID) if err != nil || entry == nil { if err == nil && k.now().After(w.Ask.At.Add(AskLasts+time.Hour)) { said = append(said, k.endAsk(ctx, e, w, "ended: the router keeps no record of its ask (refused before it was taken, or forgotten)")) } continue } var rec routerRecord if json.Unmarshal(entry.Value, &rec) != nil || rec.State == "open" || rec.Warrant == nil { continue } said = append(said, k.decide(ctx, e, w, *rec.Warrant)) } return said, nil } // endAsk records an ask ended without the operator's choice: the record stays proposed. func (k *KB) endAsk(ctx context.Context, e *Entry, w *Record, why string) string { w = w.Clone() w.Ask.Said = why if err := k.Store.Save(ctx, Version{By: "the knowledge base", At: k.now(), Why: "the operator's ask " + why, Record: w, Insight: e.Pending != nil}, e.Pending == nil, false, e.Revision); err != nil { return fmt.Sprintf("%s: the end of its ask could not be kept (%v)", w.Key(), err) } k.emit(EventReviewed, w, "the knowledge base", "the operator's ask "+why, e.Versions+1) return fmt.Sprintf("%s: the operator's ask %s; it stays proposed", w.Key(), why) } // decide holds one closed ask's warrant to the record, and accepts the record when it is the operator's Approve. func (k *KB) decide(ctx context.Context, e *Entry, w *Record, warrant asks.Warrant) string { if warrant.Outcome != asks.OutcomeChosen { why := "ended " + string(warrant.Outcome) if warrant.Words != "" { why += " (" + warrant.Words + ")" } return k.endAsk(ctx, e, w, why) } ask := composeAsk(w, w.Ask) option, err := warrant.For(Module, ask) if err == nil { err = option.Performs(act(w, w.Ask, option.ID)) } if err != nil { k.logf("[mesh-knowledge] REFUSED the answer to the ask for %s: %v", w.Key(), err) return k.endAsk(ctx, e, w, "was answered, and the answer does not hold here: "+err.Error()) } switch option.ID { case OptionApprove: w = w.Clone() w.Ask.Said, w.Ask.Warrant = AskApproved, warrant.Says() r, err := k.accept(ctx, e, w, "the operator", "accepted on the operator's Approve after the knowledge base's review", "warrant: "+warrant.Says()) if err != nil { return err.Error() } return fmt.Sprintf("%s: %s on the operator's warrant (%s)", r.Key(), r.Status, warrant.Says()) case OptionDecline: w = w.Clone() w.Ask.Warrant = warrant.Says() return k.endAsk(ctx, e, w, "declined by the operator") } return k.endAsk(ctx, e, w, "was answered with "+option.ID+", which it does not offer") } // HeardEnd takes the router's word that one of this module's asks ended without a choice: nothing is accepted on // such a word, so it needs no proof beyond its subject. A choice is only ever taken from the router's record. func (k *KB) HeardEnd(w asks.Warrant) { if w.Asker != Module || w.Outcome == asks.OutcomeChosen { if _, err := k.Reconcile(); err != nil { k.logf("[mesh-knowledge] reading the router's answers: %v", err) } return } ctx := context.Background() k.mu.Lock() defer k.mu.Unlock() all, err := k.Store.All(ctx) if err != nil { return } for _, e := range all { r := e.Working() if r.Ask != nil && r.Ask.ID == w.Ask && r.Ask.Said == AskWaiting { k.logf("[mesh-knowledge] %s", k.decide(ctx, e, r, w)) } } }