A closing keeps the review round, get says the round, a close waits for the operator's round-5 answer (issue 784, ADR 0665)
Claude-Session: https://claude.ai/code/session_01JG73KK8HD1gufnqyFxMFdW
This commit is contained in:
@@ -311,6 +311,8 @@ type Got struct {
|
||||
// Idea is said of a research effort kept as an idea: it is not what holds (ADR 0629 §2).
|
||||
Idea string `json:"idea,omitempty"`
|
||||
Waiting string `json:"waiting,omitempty"`
|
||||
// Round is the round of the next review of the working version (ADR 0665).
|
||||
Round int `json:"round,omitempty"`
|
||||
// Retracted are the retractions the operator approved; Retracting, one waiting for the operator.
|
||||
Retracted []RetractionRow `json:"retracted,omitempty"`
|
||||
Retracting string `json:"retracting,omitempty"`
|
||||
@@ -386,11 +388,21 @@ func (k *KB) Get(a GetAsk) (*Got, error) {
|
||||
e.PendingVersion, k, last.Version)
|
||||
}
|
||||
}
|
||||
if r.Ask != nil {
|
||||
g.Waiting = "the operator's ask: " + r.Ask.Said
|
||||
if r.Ask.Said == AskWaiting && r.Ask.Held != "" {
|
||||
if a.Version == 0 {
|
||||
g.Round = e.Working().Round()
|
||||
}
|
||||
ask := r.Ask
|
||||
if a.Version == 0 && e.Pending != nil && e.Pending.Ask != nil {
|
||||
ask = e.Pending.Ask // the ask of the version being worked
|
||||
}
|
||||
if ask != nil {
|
||||
g.Waiting = "the operator's ask: " + ask.Said
|
||||
if ask.Round > 0 {
|
||||
g.Waiting = fmt.Sprintf("the operator's ask after round %d asked changes: %s", ask.Round, ask.Said)
|
||||
}
|
||||
if ask.Said == AskWaiting && ask.Held != "" {
|
||||
// Held by the router, not shown to the operator yet: said so, with why (ADR 0397, issue 926).
|
||||
g.Waiting = "the operator's ask is held by the router, not yet shown to the operator: " + r.Ask.Held
|
||||
g.Waiting = "the operator's ask is held by the router, not yet shown to the operator: " + ask.Held
|
||||
}
|
||||
}
|
||||
if a.Version == 0 {
|
||||
|
||||
@@ -85,6 +85,10 @@ func (k *KB) Close(caller string, a CloseAsk) (*Closed, error) {
|
||||
if cur.Retracting != nil {
|
||||
return nil, fmt.Errorf("%s has a retraction waiting for the operator; nothing was closed", key)
|
||||
}
|
||||
if w := e.Working(); w.Ask != nil && w.Ask.Said == AskWaiting && w.Ask.Round > 0 {
|
||||
return nil, fmt.Errorf("%s is at round %d of its review, which asked changes: the operator decides it, and no review runs before the "+
|
||||
"answer. Nothing was closed; close it after the operator's answer", key, w.Ask.Round)
|
||||
}
|
||||
want := closeLinkKind[a.To]
|
||||
var added []Link
|
||||
var refusals []Refusal
|
||||
@@ -111,7 +115,11 @@ func (k *KB) Close(caller string, a CloseAsk) (*Closed, error) {
|
||||
name = fmt.Sprintf("%s (%d)", closeSection[a.To], n)
|
||||
}
|
||||
r.Sections = append(r.Sections, Section{Name: name, Text: note})
|
||||
r.Reviews, r.Ask, r.Retracting = nil, nil, nil
|
||||
r.Reviews, r.CountFrom, r.Ask, r.Retracting = nil, 0, nil, nil
|
||||
if e.Pending != nil {
|
||||
// The closing keeps the round count of the version it replaces (ADR 0665 §1).
|
||||
r.Reviews, r.CountFrom = e.Pending.Reviews, e.Pending.CountFrom
|
||||
}
|
||||
r.NeedsOperator, r.Brief = false, nil
|
||||
r.Author = caller
|
||||
r.Writers = append([]string{}, cur.Writers...)
|
||||
@@ -243,7 +251,8 @@ func ClosingQuestion(r *Record, from string, linked []*Record) string {
|
||||
b.WriteString("the note says why it is parked as an idea. A closing to an idea takes no links: never ask for one.")
|
||||
}
|
||||
b.WriteString(" Answer changes otherwise, with findings, each naming the note or the link and saying what to change. " +
|
||||
"Do not ask for changes of taste or wording that leave the meaning as it is.\n\n")
|
||||
"Do not ask for changes of taste or wording that leave the meaning as it is.\n")
|
||||
b.WriteString(roundText(r) + "\n")
|
||||
fmt.Fprintf(&b, "The note, section %q:\n\n%s\n\n", c.Section, c.Note)
|
||||
if c.To == StatusGraduated {
|
||||
b.WriteString("The became links the effort carries, those it carried before and those the closing adds:\n")
|
||||
|
||||
@@ -160,7 +160,7 @@ func ReviewQuestion(r *Record, linked []*Record) string {
|
||||
// graduated or abandoned, which it takes once accepted) are shown apart, each named for what it is (hq issue 492).
|
||||
func reviewed(r *Record) *Record {
|
||||
c := r.Clone()
|
||||
c.Reviews, c.Ask, c.Judging, c.Drafting, c.Writers, c.Author, c.Parts = nil, nil, nil, nil, nil, "", nil
|
||||
c.Reviews, c.Ask, c.Judging, c.Drafting, c.Writers, c.Author, c.Parts, c.CountFrom = nil, nil, nil, nil, nil, "", nil, 0
|
||||
c.Extra = addExtra(c.Extra, "state in the knowledge base", c.Status+" (every record under review is; it is not the record's own status)")
|
||||
if c.Kind == KindResearch && c.Effort != "" {
|
||||
c.Extra = addExtra(c.Extra, "research status", c.Effort)
|
||||
|
||||
@@ -142,3 +142,47 @@ func TestTheRoundCountGoesOnAcrossRevisionsOfAPendingInsight(t *testing.T) {
|
||||
t.Fatalf("the third revision of the insight: %.300s", q)
|
||||
}
|
||||
}
|
||||
|
||||
// A pending version of an active effort: revisions and a closing keep the count (ADR 0665 §1), `get` says the round and
|
||||
// the ask after round 5, and a close is refused while that ask waits (§3).
|
||||
func TestARoundCountSurvivesAClosingAndAClosingWaitsForTheOperatorsAnswer(t *testing.T) {
|
||||
w := imported(t, newMemStore())
|
||||
n := w.effort(t, StatusActive)
|
||||
revise := func(i int, answer string) string {
|
||||
next := effortAsk(n, StatusActive, Section{Name: "00-overview.md", Text: fmt.Sprintf("What a roadmap entry would be, revision %d.", i)})
|
||||
if _, err := w.k.Propose("author@g14", next); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w.judge.review, w.judge.reviews = answer, nil
|
||||
w.reviewAll(t)
|
||||
return strings.Join(w.judge.reviews, "\n")
|
||||
}
|
||||
for i := 1; i <= 2; i++ {
|
||||
revise(i, changes(i))
|
||||
}
|
||||
if g, err := w.k.Get(GetAsk{Kind: KindResearch, Number: n}); err != nil || g.Round != 3 {
|
||||
t.Fatalf("get after two rounds: %+v, %v", g, err)
|
||||
}
|
||||
if _, err := w.k.Close("lead@shanks", CloseAsk{Number: n, To: StatusIdea, Note: "Parked: nothing carries it this month."}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w.judge.review, w.judge.reviews = "", nil
|
||||
w.reviewAll(t)
|
||||
if q := strings.Join(w.judge.reviews, "\n"); !strings.Contains(q, "This is round 3 of its review") || !strings.Contains(q, "finding of review 2") {
|
||||
t.Fatalf("the closing's question: %.500s", q)
|
||||
}
|
||||
|
||||
m := w.effort(t, StatusActive)
|
||||
n = m
|
||||
for i := 1; i <= 5; i++ {
|
||||
revise(i, changes(i))
|
||||
}
|
||||
g, err := w.k.Get(GetAsk{Kind: KindResearch, Number: n})
|
||||
if err != nil || !strings.Contains(g.Waiting, "after round 5 asked changes") {
|
||||
t.Fatalf("get after round 5: %+v, %v", g.Waiting, err)
|
||||
}
|
||||
if _, err := w.k.Close("lead@shanks", CloseAsk{Number: n, To: StatusIdea, Note: "Parked: nothing carries it this month."}); err == nil ||
|
||||
!strings.Contains(err.Error(), "the operator decides") {
|
||||
t.Fatalf("a close before the answer: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user