Say what each verb replaces, so the agent is pointed at it instead of a shell command (hq ADR 0245)
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
A seat's verb names the shell commands it is the mesh's way to do, and a module says it for its own tools in its manifest; the tools verb and module list --json carry both, for the mesh MCP server's search, the agent's instructions and the guard on its shell.
This commit is contained in:
@@ -426,6 +426,13 @@ type Manifest struct {
|
||||
// module claiming a seat answers what that seat's protocol promises (novox/hq ADR 0118).
|
||||
Tools []string `json:"tools,omitempty"`
|
||||
|
||||
// Replaces says, for a tool of this module's own, the shell commands it is the mesh's way to do —
|
||||
// `{"docker_logs": ["docker logs"]}` — as a seat's verb says it in its definition (novox/hq ADR
|
||||
// 0241). A seat's verb carries its own: what a role replaces is the role's, so a module never says it
|
||||
// for a verb it serves under a claim. The console's search, the agent's instructions and the guard on
|
||||
// its shell are built from both.
|
||||
Replaces map[string][]string `json:"replaces,omitempty"`
|
||||
|
||||
// Instances says whether this module's instances are the same anywhere — `interchangeable` —
|
||||
// so a call that names no machine may be answered by any of them (novox/hq ADR 0160). A fact
|
||||
// about the software, not about the bus: a stateless web tool says it; a database does not,
|
||||
@@ -1692,6 +1699,7 @@ func ParseManifest(raw []byte) (Manifest, error) {
|
||||
}
|
||||
}
|
||||
problems = append(problems, invokeProblems(m)...)
|
||||
problems = append(problems, replacesProblems(m)...)
|
||||
problems = append(problems, endpointNameProblems(m)...)
|
||||
problems = append(problems, RouteProblems(m)...)
|
||||
for _, port := range m.Guards {
|
||||
@@ -2306,6 +2314,53 @@ func EndpointPort(m Manifest, name string) (int, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// MaxReplaced is the longest command a tool may say it replaces: a command's name and the words that
|
||||
// make it this command, never a script.
|
||||
const MaxReplaced = 80
|
||||
|
||||
// replacesProblems judges what a module says its tools replace (novox/hq ADR 0245): each key a tool it
|
||||
// declares, each entry a command line of one line, short, and said once.
|
||||
func replacesProblems(m Manifest) []string {
|
||||
var problems []string
|
||||
tools := map[string]bool{}
|
||||
for _, t := range m.Tools {
|
||||
tools[t] = true
|
||||
}
|
||||
keys := make([]string, 0, len(m.Replaces))
|
||||
for k := range m.Replaces {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, tool := range keys {
|
||||
if !tools[tool] {
|
||||
problems = append(problems, fmt.Sprintf("%s says what %q replaces, and declares no such tool: "+
|
||||
"a module says it for a tool in its `tools`; a seat's verb says it in the seat's definition "+
|
||||
"(novox/hq ADR 0245)", m.Module, tool))
|
||||
continue
|
||||
}
|
||||
if len(m.Replaces[tool]) == 0 {
|
||||
problems = append(problems, fmt.Sprintf("%s says %s replaces nothing: leave it out", m.Module, tool))
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, c := range m.Replaces[tool] {
|
||||
c = strings.TrimSpace(c)
|
||||
switch {
|
||||
case c == "":
|
||||
problems = append(problems, fmt.Sprintf("%s: %s replaces an empty command", m.Module, tool))
|
||||
case strings.ContainsAny(c, "\n\r"):
|
||||
problems = append(problems, fmt.Sprintf("%s: %s replaces %q, which is more than one line", m.Module, tool, c))
|
||||
case len(c) > MaxReplaced:
|
||||
problems = append(problems, fmt.Sprintf("%s: %s replaces %q, longer than %d characters: "+
|
||||
"the command's name and the words that make it this command", m.Module, tool, c, MaxReplaced))
|
||||
case seen[c]:
|
||||
problems = append(problems, fmt.Sprintf("%s: %s replaces %q twice", m.Module, tool, c))
|
||||
}
|
||||
seen[c] = true
|
||||
}
|
||||
}
|
||||
return problems
|
||||
}
|
||||
|
||||
// invokeProblems judges what a module says it calls (novox/hq ADR 0152).
|
||||
//
|
||||
// Refused here, in the manifest's words, rather than at the next composition of the bus's user
|
||||
|
||||
Reference in New Issue
Block a user