Progress: an unread design is not cached and is warned of at every level; head is capped (issue 1947)
mesh/check being carried to 7c0ce2fe218b on 980ade933853 | from 1da83c29ddf9
mesh/delivery merged: source.main moved to novox/mesh-catalog@980ade933853
mesh/check being carried to 7c0ce2fe218b on 980ade933853 | from 1da83c29ddf9
mesh/delivery merged: source.main moved to novox/mesh-catalog@980ade933853
This commit is contained in:
@@ -107,9 +107,12 @@ func newBusWorld(t *testing.T) *busWorld {
|
||||
return map[string]any{"folders": f, "documents": d}, err
|
||||
})
|
||||
answer("records.records_read", func(body json.RawMessage) (any, error) {
|
||||
var a struct{ Path string }
|
||||
var a struct {
|
||||
Path string
|
||||
Head int
|
||||
}
|
||||
_ = json.Unmarshal(body, &a)
|
||||
c, commit, err := records.Read(a.Path)
|
||||
c, commit, err := records.ReadHead(a.Path, a.Head)
|
||||
return map[string]any{"content": c, "commit": commit}, err
|
||||
})
|
||||
j := &judge{}
|
||||
|
||||
@@ -29,6 +29,17 @@ type Design struct {
|
||||
Unread string
|
||||
}
|
||||
|
||||
// unreadWarnings says each design whose head was not read, so none drops out of an answer silently.
|
||||
func unreadWarnings(ds []*Design) []string {
|
||||
var out []string
|
||||
for _, d := range ds {
|
||||
if d.Unread != "" {
|
||||
out = append(out, d.Unread)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// DesignHeadBytes is how much of a design is read: its frontmatter and its title lead it, and its milestones are the
|
||||
// tracker's records, so the rest is never needed.
|
||||
const DesignHeadBytes = 16 << 10
|
||||
@@ -58,12 +69,13 @@ func parseDesign(path, content string) *Design {
|
||||
d.Number, _ = strconv.Atoi(m[1])
|
||||
}
|
||||
lines := strings.Split(content, "\n")
|
||||
body := 0
|
||||
body, closed := 0, false
|
||||
if len(lines) > 0 && strings.TrimSpace(lines[0]) == "---" {
|
||||
for i := 1; i < len(lines); i++ {
|
||||
l := lines[i]
|
||||
if strings.TrimSpace(l) == "---" {
|
||||
body = i + 1
|
||||
closed = true
|
||||
break
|
||||
}
|
||||
if v, ok := strings.CutPrefix(l, "status:"); ok {
|
||||
@@ -74,6 +86,9 @@ func parseDesign(path, content string) *Design {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(lines) > 0 && strings.TrimSpace(lines[0]) == "---" && !closed {
|
||||
d.Unread = fmt.Sprintf("the frontmatter of %s does not close in the part read: its state and decisions are not known here", path)
|
||||
}
|
||||
for i := body; i < len(lines) && d.Title == ""; i++ {
|
||||
if m := titleLine.FindStringSubmatch(strings.TrimSpace(lines[i])); m != nil {
|
||||
d.Title = strings.TrimSpace(m[1])
|
||||
@@ -171,7 +186,9 @@ func (k *KB) designs(all bool, number int) ([]*Design, string, error) {
|
||||
} else {
|
||||
d = parseDesign(p, content)
|
||||
}
|
||||
c.byPath[p] = d
|
||||
if d.Unread == "" {
|
||||
c.byPath[p] = d
|
||||
}
|
||||
k.progReads++
|
||||
}
|
||||
out = append(out, d)
|
||||
|
||||
@@ -393,6 +393,7 @@ func (k *KB) progressMesh(p *Progress) error {
|
||||
return err
|
||||
}
|
||||
p.Source = fmt.Sprintf("the issue tracker's milestone records, and the designs in %s at hq %s", DesignsFolder, short(commit))
|
||||
p.Warnings = append(p.Warnings, unreadWarnings(ds)...)
|
||||
var with []*Design
|
||||
var without []string
|
||||
for _, d := range ds {
|
||||
@@ -520,6 +521,7 @@ func (k *KB) progressRecord(p *Progress, kind string, n int) error {
|
||||
return err
|
||||
}
|
||||
p.Source = fmt.Sprintf("the knowledge base, the designs at hq %s and the issue tracker's links", short(commit))
|
||||
p.Warnings = append(p.Warnings, unreadWarnings(ds)...)
|
||||
var designs []string
|
||||
for _, d := range ds {
|
||||
for _, dn := range d.Decisions {
|
||||
|
||||
@@ -42,6 +42,15 @@ func (w withDesigns) Read(path string) (string, string, error) {
|
||||
return c, commit, err
|
||||
}
|
||||
|
||||
func (w withDesigns) ReadHead(path string, n int) (string, string, error) {
|
||||
if c, commit, err := w.base.ReadHead(path, n); err == nil {
|
||||
return c, commit, nil
|
||||
}
|
||||
c, _, err := w.designs.ReadHead(path, n)
|
||||
commit, _ := w.base.Standing()
|
||||
return c, commit, err
|
||||
}
|
||||
|
||||
// seatsWorld plays the issue tracker and mesh-delivery from the captured answers, and counts what it is asked.
|
||||
type seatsWorld struct {
|
||||
mu sync.Mutex
|
||||
@@ -335,6 +344,12 @@ func TestProgressOfADesignMinimalAndDetailed(t *testing.T) {
|
||||
!strings.Contains(bp.Tree, "design 47") || !strings.Contains(bp.Tree, "R6") {
|
||||
t.Fatalf("an unreadable design: %v %+v", err, bp)
|
||||
}
|
||||
if mp, err := kb.Progress(ProgressAsk{Of: "mesh"}); err != nil || !strings.Contains(strings.Join(mp.Warnings, "\n"), "does not read") {
|
||||
t.Fatalf("the mesh level drops an unread design silently: %v %v", err, mp.Warnings)
|
||||
}
|
||||
if d := parseDesign(DesignsFolder+"/47-x.md", "---\nstatus: in-progress\n"); d.Unread == "" {
|
||||
t.Errorf("a frontmatter cut before its close is not said")
|
||||
}
|
||||
lines := strings.Split(p.Tree, "\n")
|
||||
if !strings.HasPrefix(lines[0], "✗ design 47 · Delivery: from a commit to delivered — ") {
|
||||
t.Fatalf("first line %q", lines[0])
|
||||
|
||||
@@ -52,7 +52,7 @@ func tools(r *Records) []stdio.Tool {
|
||||
return r.Search(strArg(a, "query"), limit)
|
||||
}},
|
||||
{Name: "records_read",
|
||||
Description: "One document, whole, by its path in the repository — a decision record, a design document, an issue report.",
|
||||
Description: "One document by its path (whole, or its first part with head) in the repository — a decision record, a design document, an issue report.",
|
||||
Input: map[string]any{"path": str("the document's path, e.g. 02-DECISIONS/0025-....md"),
|
||||
"head": map[string]any{"type": "number", "description": "only the first this many bytes, cut at a line end (optional); the answer says partial"}},
|
||||
Run: func(a map[string]any) (any, error) {
|
||||
|
||||
@@ -343,6 +343,7 @@ func (r *Records) ReadHead(p string, head int) (Document, error) {
|
||||
return Document{}, fmt.Errorf("the repository holds no %s — `records_list` says what it holds", clean)
|
||||
}
|
||||
d := Document{Path: clean, Content: string(raw), Commit: r.Standing().Commit}
|
||||
head = min(head, MostBytes)
|
||||
if head > 0 && head < len(d.Content) {
|
||||
cut := d.Content[:head]
|
||||
if i := strings.LastIndex(cut, "\n"); i > 0 {
|
||||
|
||||
Reference in New Issue
Block a user