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
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.
129 lines
3.9 KiB
Go
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
|
|
}
|