mesh-knowledge: the import keeps every field and takes clauses only from the Decision section's own list, and can repair what it held (hq issue 487)
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 import at hq f0892019 lost reconstructed, amended and a research effort's touches, held rests-on only as a
citation, took eight records' clauses from a numbered list inside a ### subsection, and left the 11 records with
no Decision section clause-less with nothing queued. Each is held now; refresh repairs a record only the import
ever wrote, and never one changed since.
This commit is contained in:
2026-10-11 12:18:03 +02:00
parent 300406e0dd
commit 1cc0ab369f
26 changed files with 3592 additions and 80 deletions
@@ -78,9 +78,50 @@ var whichConfirmSchema = map[string]any{
"required": []string{"exact", "reason"},
}
// DraftQuestion is the first judgement's question: the record's Decision section, nothing else of the mesh.
func DraftQuestion(r *Record, section, returned string) string {
// MostDraftSource is the most text a record is drafted from in one judgement, which takes at most 64 KiB.
const MostDraftSource = 48 << 10
// draftSource is what a record's clauses are drafted from: its Decision section, or, for a record that has none
// (hq issue 487), what it decides across its sections — all but its preamble, consequences and references.
func draftSource(r *Record) (text string, whole bool) {
if section, ok := decisionSection(r); ok && strings.TrimSpace(section) != "" {
return section, false
}
var b strings.Builder
for _, s := range r.Sections {
name := strings.ToLower(strings.TrimSpace(s.Name))
if name == "preamble" || strings.HasPrefix(name, "consequences") || strings.HasPrefix(name, "references") || strings.TrimSpace(s.Text) == "" {
continue
}
fmt.Fprintf(&b, "## %s\n\n%s\n\n", s.Name, strings.TrimSpace(s.Text))
}
return strings.TrimSpace(b.String()), true
}
// sourceName is how a question names what it hands the judgement.
func sourceName(whole bool) string {
if whole {
return "The record's sections"
}
return "The Decision section"
}
// DraftQuestion is the first judgement's question: the record's Decision section — or, where it has none, its
// sections — and nothing else of the mesh.
func DraftQuestion(r *Record, section, returned string, whole bool) string {
var b strings.Builder
if whole {
fmt.Fprintf(&b, "Below are the sections of a decision record, %s: %q. It has no Decision section: what it decides is written "+
"as prose across its sections. Write what it decides as numbered clauses: each one statement, one sentence, with a lead of a "+
"few words naming what is decided. A clause says nothing the sections do not say: no inference, no context from elsewhere, "+
"nothing added. Every decision the sections make is in one clause; a sentence that only explains, or describes what was, is "+
"in none. Keep the record's own words where you can.\n", r.Key(), r.Title)
if returned != "" {
fmt.Fprintf(&b, "\nAn earlier draft was sent back, with this reason: %s\n", returned)
}
b.WriteString("\n" + sourceName(true) + ":\n\n" + section)
return b.String()
}
fmt.Fprintf(&b, "Below is the Decision section of a decision record, %s: %q. It is written as prose. Write what it decides as numbered "+
"clauses: each one statement, one sentence, with a lead of a few words naming what is decided. A clause says nothing the section "+
"does not say: no inference, no context from elsewhere, nothing added. Every decision the section makes is in one clause; a "+
@@ -93,12 +134,16 @@ func DraftQuestion(r *Record, section, returned string) string {
}
// ConfirmQuestion is the second judgement's question: the record and the drafts, nothing else.
func ConfirmQuestion(r *Record, section string, drafts []Clause) string {
func ConfirmQuestion(r *Record, section string, drafts []Clause, whole bool) string {
var b strings.Builder
fmt.Fprintf(&b, "Below are the Decision section of a decision record, %s: %q, and clauses drafted from it by someone else. For each "+
"clause, answer whether the section says exactly that: exact is true only when the clause says nothing the section does not, "+
"and leaves out nothing that changes its meaning. When it is not exact, say in reason what the section says instead.\n\n"+
"The Decision section:\n\n%s\n\nThe drafted clauses:\n\n", r.Key(), r.Title, section)
what := "the Decision section of a decision record"
if whole {
what = "the sections of a decision record that has no Decision section"
}
fmt.Fprintf(&b, "Below are %s, %s: %q, and clauses drafted from it by someone else. For each "+
"clause, answer whether the text says exactly that: exact is true only when the clause says nothing the text does not, "+
"and leaves out nothing that changes its meaning. When it is not exact, say in reason what the text says instead.\n\n"+
"%s:\n\n%s\n\nThe drafted clauses:\n\n", what, r.Key(), r.Title, sourceName(whole), section)
for _, c := range drafts {
fmt.Fprintf(&b, "%d. %s\n", c.N, c.Text)
}
@@ -155,10 +200,15 @@ func (k *KB) draftOne(ctx context.Context, key Key) (string, error) {
return "", err
}
r := e.Current.Clone()
section, ok := decisionSection(r)
if !ok {
r.Drafting = &Drafting{State: DraftDone, Reason: "it has no Decision section", At: k.now()}
return k.saveDraft(ctx, e, r, EventDrafted, "no Decision section to draft from")
section, whole := draftSource(r)
if section == "" || len(section) > MostDraftSource {
why := fmt.Sprintf("no Decision section, and its sections hold %d bytes of what it decides, more than one judgement takes (%d): "+
"it has no clauses", len(section), MostDraftSource)
if section == "" {
why = "no Decision section, and no section saying what it decides: it has no clauses"
}
r.Drafting = &Drafting{State: DraftDone, Reason: why, At: k.now()}
return k.saveDraft(ctx, e, r, EventDrafted, why)
}
model := k.judgeModel()
fail := func(step string, err error) (string, error) {
@@ -177,7 +227,7 @@ func (k *KB) draftOne(ctx context.Context, key Key) (string, error) {
// A failed record goes back to the step it failed at: confirming when it holds drafts, drafting otherwise.
confirming := r.Drafting.State == DraftDrafted || (r.Drafting.State == DraftFailed && hasDrafts(r))
if !confirming {
answer, by, err := k.Judge(DraftQuestion(r, section, r.Drafting.Returned), draftSchema, model)
answer, by, err := k.Judge(DraftQuestion(r, section, r.Drafting.Returned, whole), draftSchema, model)
if err != nil {
return fail("drafting", err)
}
@@ -202,7 +252,7 @@ func (k *KB) draftOne(ctx context.Context, key Key) (string, error) {
r.Drafting = &Drafting{State: DraftDrafted, Drafter: by, Returned: r.Drafting.Returned, Tries: r.Drafting.Tries, At: k.now()}
return k.saveDraft(ctx, e, r, EventDrafted, fmt.Sprintf("%d clauses drafted by %s", len(r.Clauses), by))
}
answer, by, err := k.Judge(ConfirmQuestion(r, section, r.Clauses), confirmSchema, model)
answer, by, err := k.Judge(ConfirmQuestion(r, section, r.Clauses, whole), confirmSchema, model)
if err != nil {
return fail("confirming", err)
}
@@ -338,13 +388,14 @@ func (k *KB) judgeChange(ctx context.Context, from Key, i int) (string, error) {
return "", nil // the older record's clauses are not confirmed yet: judged once they are
}
model := k.judgeModel()
newer, _ := decisionSection(r)
newer, whole := draftSource(r)
var b strings.Builder
fmt.Fprintf(&b, "%s says it replaces part of an older record, %s. Below are the clauses of %s and the Decision section of %s.\n\n", r.Key(), older.Key(), older.Key(), r.Key())
fmt.Fprintf(&b, "%s says it replaces part of an older record, %s. Below are the clauses of %s and %s of %s.\n\n", r.Key(), older.Key(), older.Key(),
strings.ToLower(sourceName(whole)), r.Key())
for _, c := range older.Clauses {
fmt.Fprintf(&b, "%d. %s\n", c.N, c.Text)
}
fmt.Fprintf(&b, "\nThe Decision section of %s:\n\n%s\n", r.Key(), newer)
fmt.Fprintf(&b, "\n%s of %s:\n\n%s\n", sourceName(whole), r.Key(), newer)
if l.Source == LinkPending {
answer, by, err := k.Judge(b.String()+"\nWhich of the older record's clauses does the newer record replace part of? Name their numbers.", whichSchema, model)
if err != nil {