Say the terminal explicitly, only from a login session, and name the unannounced pull request (hq ADR 0272)
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 delivered

- commandEnvironment takes the terminal as a bool instead of reading an
  empty verb as one; every non-terminal line names its verb and is stripped
  of MESH_CLI_TERMINAL, and a test with the mark set in the serving
  environment fails when that strip is taken out.
- On the control-node the operator's account is the terminal only from a
  login session, as the node-engine reads it from the kernel's cgroup; the
  tool runner and the account's user units run as the operator too, and are
  ordinary calls. The request carries `session` (field-name tests on both
  sides).
- A pull request the forge never announced is named with its number in
  the condition's headline (hq issue 347), from the stalled line's
  `number`, which mesh-delivery sends.
This commit is contained in:
jochen
2026-10-09 13:41:32 +02:00
parent 63e85b25e6
commit 51c8c7ec52
8 changed files with 88 additions and 30 deletions
+8 -6
View File
@@ -33,12 +33,14 @@ var deliveryOwnerWithin = 10 * time.Second
// stalledLine is one delivery past its bound, as mesh-delivery's `stalled` says it.
type stalledLine struct {
ID string `json:"id"`
State string `json:"state"`
For string `json:"for"`
Bound string `json:"bound"`
H2 string `json:"h2"`
Says string `json:"says"`
ID string `json:"id"`
// Number is the pull request's, for a line of a head the forge never announced (novox/hq issue 347).
Number int `json:"number,omitempty"`
State string `json:"state"`
For string `json:"for"`
Bound string `json:"bound"`
H2 string `json:"h2"`
Says string `json:"says"`
}
// operatorsOnly is whether the table leaves H2 nothing to do for the line: the state is the operator's.
+9 -3
View File
@@ -71,8 +71,14 @@ func judgeCLI(node string, asked link.CLIAsked, nodes []inventory.Node, control
"terminal is the one control-node's operator account", len(control))}
}
if control[0] == node {
return cliVerdict{terminal: true, why: fmt.Sprintf("the controller's terminal: %s on the control-node %s",
asked.Account, node)}
// **A person at a terminal, not a service of the operator's** (review of ADR 0272): the tool runner and the
// account's user units run as the operator too, and only a login session is the terminal.
if asked.Session == "" {
return cliVerdict{why: fmt.Sprintf("not the controller's terminal: %s on %s asked from no login session — a "+
"service or a user unit running as the operator, not a person at a terminal", asked.Account, node)}
}
return cliVerdict{terminal: true, why: fmt.Sprintf("the controller's terminal: %s on the control-node %s, "+
"login session %s", asked.Account, node, asked.Session)}
}
return cliVerdict{why: fmt.Sprintf("not the controller's terminal: agents on %s may run as %s, so a "+
"terminal-only change is made from the control-node %s (novox/hq ADR 0272)", node, asked.Account, control[0])}
@@ -148,7 +154,7 @@ func runForMeshCLI(ctx context.Context, node string, asked link.CLIAsked, v cliV
verb, line = cliVerb, composed
}
cmd := selfCommand(ctx, line)
cmd.Env = commandEnvironment(fmt.Sprintf("%s through mesh-cli on %s", asked.Account, node), verb)
cmd.Env = commandEnvironment(fmt.Sprintf("%s through mesh-cli on %s", asked.Account, node), verb, v.terminal)
// No standard input: a command that reads one gets nothing, and fails saying so (ADR 0272 §5).
cmd.Stdin = nil
var stdout, stderr bytes.Buffer
+40 -1
View File
@@ -25,7 +25,7 @@ var cliNodes = []inventory.Node{
}
func asked(account string, uid uint32, line ...string) link.CLIAsked {
return link.CLIAsked{Line: line, Account: account, UID: uid}
return link.CLIAsked{Line: line, Account: account, UID: uid, Session: "session-1.scope"}
}
// Who is the controller's terminal, and who is an ordinary call or refused (novox/hq ADR 0272 §4).
@@ -264,3 +264,42 @@ func TestTheCallsVerbNeverShowsAMeshCLILinesAnswer(t *testing.T) {
t.Fatalf("calls showed a mesh-cli line's answer: %s", said)
}
}
// **Only the terminal's line carries the terminal's mark** (review of ADR 0272): a mark the serving controller's
// environment holds — leaked, or set by anything — is stripped from every other command line it runs, a verb's and
// an ordinary mesh-cli line alike, so neither reads as the terminal.
func TestTheTerminalsMarkIsStrippedFromEveryOtherLine(t *testing.T) {
t.Setenv(echoEnvironment, "1")
t.Setenv(cliTerminalVar, "1")
t.Setenv(servedVar, "1")
for _, env := range [][]string{commandEnvironment("someone", "status", false)} {
for _, kv := range env {
if strings.HasPrefix(kv, cliTerminalVar+"=") {
t.Fatalf("a verb's line carries the terminal's mark: %s", kv)
}
}
}
a := runForMeshCLI(context.Background(), "laptop", asked("operator", 1000, "status"), cliVerdict{why: "not the terminal"})
if got := string(a.Stdout); !strings.Contains(got, "terminal=false") || !strings.Contains(got, `verb="mesh-cli"`) {
t.Fatalf("an ordinary line with the mark in the serving environment ran as %s", got)
}
a = runForMeshCLI(context.Background(), "control", asked("operator", 1000, "status"), cliVerdict{terminal: true})
if got := string(a.Stdout); !strings.Contains(got, "terminal=true") {
t.Fatalf("the terminal's line ran as %s", got)
}
}
// **Only a login session is the terminal** (review of ADR 0272): the operator's account on the control-node, asking
// from a service — the tool runner, a user unit — and not a login session, is an ordinary call.
func TestOnlyALoginSessionIsTheTerminal(t *testing.T) {
control := []string{"control"}
v := judgeCLI("control", link.CLIAsked{Line: []string{"status"}, Account: "operator", UID: 1000}, cliNodes, control)
if v.terminal || v.refused != "" || !strings.Contains(v.why, "login session") {
t.Fatalf("a line from no login session reads %+v", v)
}
v = judgeCLI("control", link.CLIAsked{Line: []string{"status"}, Account: "operator", UID: 1000, Session: "session-3.scope"},
cliNodes, control)
if !v.terminal {
t.Fatalf("a line from a login session on the control-node reads %+v", v)
}
}
+8 -5
View File
@@ -758,11 +758,14 @@ func stalledWords(l stalledLine, o conditions.Observation) (headline, explanatio
if o.Resolver == conditions.ResolverOperator {
needs = "push a new commit to its branch; the forge announces it and the mesh checks it."
}
return fmt.Sprintf("A pull request of %s has had no merge check %s", name, long),
fmt.Sprintf("A pull request of %s has been open %s on a branch that requires the merge check, and the "+
"mesh was never asked to check it: the forge never announced it. It cannot merge until it is checked.",
name, long),
fmt.Sprintf("The pull request of %s has a merge check now, or is closed", name), needs, nil
pull := "A pull request of " + name
if l.Number > 0 {
pull = fmt.Sprintf("Pull request %s #%d", name, l.Number)
}
return fmt.Sprintf("%s has had no merge check %s", pull, long),
fmt.Sprintf("%s has been open %s on a branch that requires the merge check, and the mesh was never asked "+
"to check it: the forge never announced it. It cannot merge until it is checked.", pull, long),
fmt.Sprintf("%s has a merge check now, or is closed", pull), needs, nil
}
held := l.State
if held == "" {
+3 -2
View File
@@ -314,7 +314,7 @@ func TestANeedNoNotificationAnswersNamesTheMeshMCPServer(t *testing.T) {
// as a stalled line in state `unannounced` — no delivery exists, so there is nothing to stop, release or close —
// and the operator's one act is a new commit on its branch, which the forge announces.
func TestAnUnannouncedPullRequestSaysToPushANewCommit(t *testing.T) {
l := stalledLine{ID: "novox/hq@bfe82315f42c", State: "unannounced", For: "11m0s", Bound: "10m0s",
l := stalledLine{ID: "novox/hq@bfe82315f42c", Number: 243, State: "unannounced", For: "11m0s", Bound: "10m0s",
H2: "none: the forge never announced it, so there is no delivery to close — the operator's",
Says: "novox/hq#243 is open on main, which requires the merge check, and its head has had no merge check"}
obs := stalledObservations([]stalledLine{l})
@@ -325,7 +325,8 @@ func TestAnUnannouncedPullRequestSaysToPushANewCommit(t *testing.T) {
if strings.Contains(o.Needs, "stop") || strings.Contains(o.Needs, "release") || !strings.Contains(o.Needs, "commit") {
t.Fatalf("it says to %q", o.Needs)
}
if !strings.Contains(o.Headline, "no merge check") || !strings.Contains(o.Explanation, "never") {
if !strings.Contains(o.Headline, "no merge check") || !strings.Contains(o.Headline, "#243") ||
!strings.Contains(o.Explanation, "never") {
t.Fatalf("it reads %q / %q", o.Headline, o.Explanation)
}
}
+11 -12
View File
@@ -931,27 +931,26 @@ func isWhyFlag(word string) bool {
// commandEnvironment is the environment of a command line this controller runs for someone: its own — the
// stores' credentials, the bus, the broker, everything a command run from a shell beside it would have, because it
// is that — with who asked, and the verb it came through. An empty verb is the controller's terminal (novox/hq ADR
// 0272 §4): no `MESH_VERB` at all, whatever this process was started with.
// is that — with who asked, and how it came.
//
// The terminal's line is also not the serving controller's (servedVar), and carries cliTerminalVar, so what reads
// whether it was started at the terminal (startedAtTheTerminal) reads yes; every other line is stripped of that mark.
func commandEnvironment(caller, verb string) []string {
// **terminal** is said, never inferred (novox/hq ADR 0272): only a line mesh-cli asked as the controller's terminal
// passes true. Its line has no `MESH_VERB`, not the served mark ADR 0266 puts on everything the serving controller
// starts, and the terminal's mark (cliTerminalVar), so startedAtTheTerminal reads yes. Every other line names its
// verb, and is stripped of the terminal's mark whatever this process's environment holds.
func commandEnvironment(caller, verb string, terminal bool) []string {
env := make([]string, 0, len(os.Environ())+3)
for _, kv := range os.Environ() {
if strings.HasPrefix(kv, verbVar+"=") || strings.HasPrefix(kv, link.CallerVar+"=") ||
strings.HasPrefix(kv, cliTerminalVar+"=") || (verb == "" && strings.HasPrefix(kv, servedVar+"=")) {
strings.HasPrefix(kv, cliTerminalVar+"=") || (terminal && strings.HasPrefix(kv, servedVar+"=")) {
continue
}
env = append(env, kv)
}
env = append(env, link.CallerVar+"="+caller)
if verb != "" {
env = append(env, verbVar+"="+verb)
} else {
env = append(env, cliTerminalVar+"=1")
if terminal {
return append(env, cliTerminalVar+"=1")
}
return env
return append(env, verbVar+"="+verb)
}
// runVerb runs this binary with the given command line and gathers what it said.
@@ -977,7 +976,7 @@ func runVerb(ctx context.Context, argv []string) (verbAnswer, error) {
if verb == "" {
verb = argv[0]
}
cmd.Env = commandEnvironment(caller+", through the "+catalogue.ControllerSeatName+" seat", verb)
cmd.Env = commandEnvironment(caller+", through the "+catalogue.ControllerSeatName+" seat", verb, false)
// Two buffers, one answer. What the command *says* is both streams, in the order a person at
// a shell would read them; what it *answers as data* is standard output alone — `status --json`
// prints its warnings beside the document, and a JSON parsed from the two together parsed