From f75e1a91d957362e6d418db587bedd2de8683f0e Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 15 Oct 2026 21:29:55 +0200 Subject: [PATCH] Carry the proposal day only into the dated rules, so an old effort's marked insight stands (hq issue 844) --- .../cmd/mesh-knowledge/active_effort_test.go | 25 +++++++++++++++++++ .../mesh-knowledge/cmd/mesh-knowledge/kb.go | 11 ++++---- .../cmd/mesh-knowledge/rules.go | 9 ++++++- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/active_effort_test.go b/modules/mesh-knowledge/cmd/mesh-knowledge/active_effort_test.go index ead658a6..3302dec0 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/active_effort_test.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/active_effort_test.go @@ -123,3 +123,28 @@ func TestAChangesVerdictLeavesTheServedVersionServedAndGraduatingNeedsABecameLin t.Fatalf("graduated without a became link: %v", err) } } + +// An earlier marked insight in an old effort's text does not predate the effort, and a new version is accepted. +func TestAnOldActiveEffortWithAMarkedInsightTakesANewVersion(t *testing.T) { + w := imported(t, newMemStore()) + w.clock = time.Date(2026, 10, 1, 9, 0, 0, 0, time.UTC) + r, err := w.k.ReserveNumber("author@g14", KindResearch, "an old effort") + if err != nil { + t.Fatal(err) + } + overview := Section{Name: "00-overview.md", Text: "What an inference layer would be.\n\n**Progressive insight — 2026-10-05.** A fact was corrected."} + first := effortAsk(r.Number, StatusActive, overview) + first.Date = "2026-10-01" + w.accepted(t, "author@g14", first) + w.clock = time.Date(2026, 10, 15, 9, 0, 0, 0, time.UTC) + next := effortAsk(r.Number, StatusActive, overview, Section{Name: "01-findings.md", Text: "A new finding."}) + next.Date = "2026-10-01" + if _, err := w.k.Propose("author@g14", next); err != nil { + t.Fatalf("a new version with an earlier marked insight: %v", err) + } + w.reviewAll(t) + e := mustGet(t, w.k.Store, Key{KindResearch, r.Number}) + if e.Pending != nil || e.Current.Section("01-findings.md") != "A new finding." || e.Current.Date != "2026-10-01" { + t.Fatalf("after the review: pending %v, date %s", e.Pending != nil, e.Current.Date) + } +} diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/kb.go b/modules/mesh-knowledge/cmd/mesh-knowledge/kb.go index c11eece6..4c469359 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/kb.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/kb.go @@ -379,14 +379,13 @@ func (k *KB) Propose(caller string, a ProposeAsk) (*Proposed, error) { if !current && a.Kind == KindResearch && r.Effort == "" { r.Effort = held.Current.Status } - judged := r + // A new version of an active effort is new text: the dated rules hold it from the day it is proposed, while the + // record keeps its own date (novox/hq issue 844). + day := r.Date if r.Pending != nil && !r.IsInsight() { - // A new version of an active effort is new text: the dated rules hold it from the day it is proposed, while - // the record keeps its own date (novox/hq issue 844). - judged = r.Clone() - judged.Date = k.now().Format("2006-01-02") + day = k.now().Format("2006-01-02") } - refusals = append(refusals, JudgeRecord(judged, held, k.lookup(ctx), ref)...) + refusals = append(refusals, JudgeRecordOn(r, held, k.lookup(ctx), ref, day)...) if raw, _ := json.Marshal(r); len(raw) > MostRecordBytes { refusals = append(refusals, Refusal{Rule: "size", Says: fmt.Sprintf("the record is %d bytes; a record holds at most %d", len(raw), MostRecordBytes)}) } diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/rules.go b/modules/mesh-knowledge/cmd/mesh-knowledge/rules.go index 3f657d63..fbacf6c0 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/rules.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/rules.go @@ -123,9 +123,16 @@ func allText(r *Record) string { // JudgeRecord holds a proposed record to the 30 rules. held is the entry its number holds (a reservation, the // proposal being revised, or the accepted record an insight corrects); lookup reads every other record. func JudgeRecord(r *Record, held *Entry, lookup Lookup, ref *Reference) []Refusal { + return JudgeRecordOn(r, held, lookup, ref, r.Date) +} + +// JudgeRecordOn is JudgeRecord with the day the dated rules are held from: the record's own day for a new +// record, the day of the proposal for a new version of an active research effort (novox/hq issue 844). The rules +// that read the record's date (the date and insight-form rules) keep reading r.Date. +func JudgeRecordOn(r *Record, held *Entry, lookup Lookup, ref *Reference, day string) []Refusal { var out []Refusal refuse := func(rule, format string, a ...any) { - if Holds(rule, r.Kind, r.Date) { + if Holds(rule, r.Kind, day) { out = append(out, Refusal{Rule: rule, Says: fmt.Sprintf(format, a...)}) } }