mesh-knowledge: review every proposal in a judgement of its own, and serve no review verb (hq issue 425, ADR 0290 as updated)
mesh/merge-gate pass: builds mesh-knowledge → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds mesh-knowledge → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
The mesh proves which machine called, not which agent on it (hq issue 365), so a review verb could not tell a reviewer from the author. Each version proposed is now judged by claude-code.claude_code_judge in a separate call that sees only the record, the records it links and the rules: approve accepts (or asks the operator for a needs-operator record), changes keeps it proposed with the findings for its author, and a judgement that cannot be had or read leaves it proposed, says so, and never counts as approval.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
// A record that needs the operator (novox/hq ADR 0290 rule 4, to-be 55 §5): once an independent review approves
|
||||
// it, the operator is asked on the router with Approve and Decline, both at the level approve, so only a channel
|
||||
// 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
|
||||
@@ -90,7 +90,7 @@ 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 an independent review. Its author says it needs your approval before it holds.", name, r.Author)
|
||||
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, "."))
|
||||
}
|
||||
@@ -130,32 +130,48 @@ func newAskID(r *Record) string {
|
||||
return fmt.Sprintf("kb-%s-%d-%s", r.Kind, r.Number, hex.EncodeToString(b[:]))
|
||||
}
|
||||
|
||||
// askOperator asks the operator to approve a reviewed record, and keeps the ask with it.
|
||||
func (k *KB) askOperator(ctx context.Context, held *Entry, w *Record, by string) (*Reviewed, error) {
|
||||
if k.Asks == nil {
|
||||
return nil, fmt.Errorf("%s needs the operator, and the operator cannot be asked from here; it stays proposed", w.Key())
|
||||
}
|
||||
// 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 published is taken back, and the review is asked
|
||||
// again after a pause: the record stays proposed.
|
||||
func (k *KB) askOperator(ctx context.Context, held *Entry, w *Record, by string) (string, error) {
|
||||
version := held.CurrentVersion
|
||||
if held.Pending != nil {
|
||||
version = held.PendingVersion
|
||||
}
|
||||
unasked := func(why string) (string, error) {
|
||||
w.Ask = nil
|
||||
w.Judging = &Judging{State: JudgingFailed, Tries: 1, Reason: why, At: k.now()}
|
||||
said := "approved by the knowledge base's review, and " + why + "; it stays proposed and is reviewed again"
|
||||
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 nil, fmt.Errorf("the ask for %s could not be made (%v); it stays proposed", w.Key(), err)
|
||||
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 nil, fmt.Errorf("the review could not be kept (%v); the operator was not asked", err)
|
||||
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 nil, fmt.Errorf("the review is kept, and the operator could not be asked (%v): %s stays proposed; review it again to ask again", err, w.Key())
|
||||
return unasked(fmt.Sprintf("the operator could not be asked (%v)", err))
|
||||
}
|
||||
return &Reviewed{Record: w.Key().String(), Verdict: VerdictApprove, Status: StatusProposed,
|
||||
Says: 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
|
||||
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.
|
||||
@@ -235,7 +251,7 @@ func (k *KB) decide(ctx context.Context, e *Entry, w *Record, warrant asks.Warra
|
||||
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 an independent review", "warrant: "+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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user