Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/hq.go
T
jschoubben ba7b455719
mesh/merge-gate pass: builds new: modules/mesh-knowledge, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compo…
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
Add mesh-knowledge, the knowledge base's first slice (hq issue 425, ADR 0290)
An agent learns what a decision says only by reading whole records. This module
holds every decision record and research effort whole in a database in the store,
with clauses that carry their own status and source, typed links read from both
ends, and every version. It answers ask, get and holds within a stated bound, and
takes a record through reserve, propose (refused on any of the 29 per-record
rules), review by someone other than the author, and acceptance, on the
operator's proven warrant when the record needs it. The 4 whole-set rules make
the module unhealthy when they fail. The import reads hq at a commit through the
records module, never overwrites, and changes nothing when run again. Prose
decisions get drafted clauses that a second judgement must confirm before they
are served.
2026-10-11 04:58:35 +02:00

129 lines
3.9 KiB
Go

package main
// hq as the knowledge base reads it: through the records module over the bus (to-be 55 §1: "it holds no
// checkout of this repository; the import reads it through the records module, as the issue tracker's import
// does"), or a checkout on disk for the terminal's dry run and the tests.
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// Records is hq as the records module serves it: where its checkout stands, what a folder holds, and one
// document whole with the commit it was read at.
type Records interface {
Standing() (string, error)
List(folder string) (folders, documents []string, err error)
Read(path string) (content, commit string, err error)
}
// busRecords is Records over the bus: the records module's tools, called as this module.
type busRecords struct{}
func (busRecords) Standing() (string, error) {
raw, err := stdio.Ask("records.records_status", map[string]any{})
if err != nil {
return "", err
}
var s struct {
Commit string `json:"commit"`
LastError string `json:"lastError"`
}
if err := json.Unmarshal(raw, &s); err != nil {
return "", fmt.Errorf("records_status answered something else: %v", err)
}
if s.Commit == "" {
return "", fmt.Errorf("the record's checkout stands at no commit yet (%s)", s.LastError)
}
return s.Commit, nil
}
func (busRecords) List(folder string) ([]string, []string, error) {
raw, err := stdio.Ask("records.records_list", map[string]any{"folder": folder})
if err != nil {
return nil, nil, err
}
var f struct {
Folders []string `json:"folders"`
Documents []string `json:"documents"`
}
if err := json.Unmarshal(raw, &f); err != nil {
return nil, nil, fmt.Errorf("records_list answered something else: %v", err)
}
return f.Folders, f.Documents, nil
}
func (busRecords) Read(path string) (string, string, error) {
raw, err := stdio.Ask("records.records_read", map[string]any{"path": path})
if err != nil {
return "", "", err
}
var d struct {
Content string `json:"content"`
Commit string `json:"commit"`
Truncated bool `json:"truncated"`
}
if err := json.Unmarshal(raw, &d); err != nil {
return "", "", fmt.Errorf("records_read answered something else: %v", err)
}
if d.Truncated {
return "", "", fmt.Errorf("%s is longer than the records module answers whole", path)
}
return d.Content, d.Commit, nil
}
// dirRecords is Records over a checkout on disk. Its commit is the file COMMIT at its root when there is one (a
// fixture copied from hq at a commit), else the checkout's HEAD, else `dir:` and the directory.
type dirRecords struct{ dir string }
func (d dirRecords) Standing() (string, error) {
if st, err := os.Stat(d.dir); err != nil || !st.IsDir() {
return "", fmt.Errorf("%s is not a checkout", d.dir)
}
if raw, err := os.ReadFile(filepath.Join(d.dir, "COMMIT")); err == nil {
return strings.TrimSpace(string(raw)), nil
}
if out, err := os.ReadFile(filepath.Join(d.dir, ".git", "HEAD")); err == nil {
ref := strings.TrimSpace(string(out))
if strings.HasPrefix(ref, "ref: ") {
if sha, err := os.ReadFile(filepath.Join(d.dir, ".git", strings.TrimPrefix(ref, "ref: "))); err == nil {
return strings.TrimSpace(string(sha)), nil
}
} else if ref != "" {
return ref, nil
}
}
return "dir:" + d.dir, nil
}
func (d dirRecords) List(folder string) ([]string, []string, error) {
entries, err := os.ReadDir(filepath.Join(d.dir, filepath.FromSlash(folder)))
if err != nil {
return nil, nil, err
}
var folders, docs []string
for _, e := range entries {
switch {
case e.IsDir():
folders = append(folders, e.Name())
case strings.HasSuffix(e.Name(), ".md"):
docs = append(docs, e.Name())
}
}
return folders, docs, nil
}
func (d dirRecords) Read(path string) (string, string, error) {
raw, err := os.ReadFile(filepath.Join(d.dir, filepath.FromSlash(path)))
if err != nil {
return "", "", err
}
commit, _ := d.Standing()
return string(raw), commit, nil
}