The composition pass never waits on marking haves, and the compose verb answers while a pass runs

The marks of the haves (a refusal, the words a module keeps) read and write each module's have in turn, and each write
walks every have: on a slow bus the pass waited minutes on them (shanks, 2026-11-05 22:22). They now run off the pass,
newest word per kind, each bounded; an ask of compose during a pass is answered at once and queues one more pass.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 22:33:21 +01:00
parent e73aae3686
commit c1b8b9d115
5 changed files with 222 additions and 3 deletions
+19 -1
View File
@@ -167,6 +167,8 @@ type Composer struct {
wait time.Duration
// asked are the compose verb's asks (ComposeNow), each answered once the pass it asks is made.
asked chan chan Pass
// passing is set while a pass is made.
passing atomic.Bool
// last is how the last pass went, under mu.
last Pass
// watching says the composer's loop runs (Watch), so an ask of a pass can be answered.
@@ -216,6 +218,9 @@ type Pass struct {
Again time.Time `json:"again,omitempty"`
// Earlier says the answer is the last pass, made less than askedWithin ago, and no new one was made for the ask.
Earlier bool `json:"earlier,omitempty"`
// Queued says a pass was running when the ask came: one more is made when it ends, and this answer is not its result.
// It says what the running pass waits on and since when.
Queued string `json:"queued,omitempty"`
}
// LastHeld is what the last pass held, each module with why; nil before a pass or when it held none.
@@ -307,6 +312,16 @@ func (c *Composer) ComposeNow(ctx context.Context) (Pass, error) {
return last, nil
}
reply := make(chan Pass, 1)
if c.passing.Load() {
// A pass runs: the ask joins the one made when it ends (all asks of the time share it), and is answered now, never
// held for the pass (issue 1965: the verb gave no answer for minutes while a pass waited on the bus).
select {
case c.asked <- reply:
default: // eight asks already wait for that pass
}
last.Queued = "a pass is running and waits on " + c.waitingOn() + "; one more is made when it ends"
return last, nil
}
select {
case c.asked <- reply:
case <-ctx.Done():
@@ -496,7 +511,10 @@ func (c *Composer) Watch(ctx context.Context, _ string) (<-chan agent.Update, er
continue
}
dirty = false
for _, u := range c.compose(ctx) {
c.passing.Store(true)
updates := c.compose(ctx)
c.passing.Store(false)
for _, u := range updates {
select {
case out <- u:
case <-ctx.Done():