K25 (D-33): the node-engine's first-views answers entries and wants, and the seat gains entry-again

Builds: design 47 G §698 (§683, §422)

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 21:36:34 +01:00
parent b76e52d30a
commit 78e61c9437
6 changed files with 308 additions and 3 deletions
+63 -1
View File
@@ -30,6 +30,7 @@ const (
VerbSeatListAgain = "seat-list-again"
VerbFirstViews = "first-views"
VerbFirstViewAgain = "first-view-again"
VerbEntryAgain = "entry-again"
VerbProcessBuilds = "process-builds"
)
@@ -46,7 +47,7 @@ const (
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbHandOver, VerbAccessAct, VerbJudgeDirectories, VerbSetuidSearch, VerbRootFree, VerbActs, VerbPackages, VerbComposition, VerbCompose, VerbComposeCandidate, VerbManifestReads, VerbSeatList, VerbSeatListAgain, VerbFirstViews, VerbFirstViewAgain, VerbProcessBuilds}
return []string{VerbHandOver, VerbAccessAct, VerbJudgeDirectories, VerbSetuidSearch, VerbRootFree, VerbActs, VerbPackages, VerbComposition, VerbCompose, VerbComposeCandidate, VerbManifestReads, VerbSeatList, VerbSeatListAgain, VerbFirstViews, VerbFirstViewAgain, VerbEntryAgain, VerbProcessBuilds}
}
// Events is every event published on the seat's subject: a new copy each call.
@@ -1366,10 +1367,41 @@ type SeatListAgainAnswer = SeatList
type FirstViewsInput struct {
}
// FirstViewsAnswerEntriesItem is a type of the contract.
type FirstViewsAnswerEntriesItem struct {
// the build's fingerprint
Fingerprint string `json:"fingerprint"`
// since when it stands in that state, RFC 3339
Since time.Time `json:"since"`
// asked of the indexer, answered, or not found by it
State string `json:"state"`
}
// The values of FirstViewsAnswerEntriesItem's state.
const (
FirstViewsAnswerEntriesItemStateAsked = "asked"
FirstViewsAnswerEntriesItemStateAnswered = "answered"
FirstViewsAnswerEntriesItemStateNotFound = "not-found"
)
// FirstViewsAnswerWantsItem is a type of the contract.
type FirstViewsAnswerWantsItem struct {
// the fingerprint wanted
Fingerprint string `json:"fingerprint"`
// since when the want is kept, RFC 3339
KeptSince time.Time `json:"kept-since"`
// the module the want is of
Module string `json:"module"`
}
// FirstViewsAnswer is what first-views answers.
type FirstViewsAnswer struct {
// one row per entry the node-engine keeps of a module's build by its fingerprint: when it asked the indexer's entry and where that stands (design 47 G 698)
Entries []FirstViewsAnswerEntriesItem `json:"entries"`
// one status per owner and state followed, as mesh-sdk's views runtime keeps it
FirstViews []map[string]any `json:"first-views"`
// the wants the node-engine keeps (design 47 G 683, 698)
Wants []FirstViewsAnswerWantsItem `json:"wants"`
}
// FirstViewAgainInput is what first-view-again takes.
@@ -1406,6 +1438,36 @@ type FirstViewAgainAnswer struct {
Read string `json:"read"`
}
// EntryAgainInput is what entry-again takes.
type EntryAgainInput struct {
// the build's fingerprint, as first-views' entries name it
Fingerprint string `json:"fingerprint"`
// why it is asked again, in plain words
Why string `json:"why"`
}
// EntryAgainAnswerAsked is the hand ask written.
type EntryAgainAnswerAsked struct {
// when it was asked, RFC 3339
At time.Time `json:"at"`
// the caller the runtime proved
By string `json:"by"`
// the build's fingerprint
Fingerprint string `json:"fingerprint"`
// the layout's version
V int64 `json:"v"`
// why it was asked again
Why string `json:"why"`
}
// EntryAgainAnswer is what entry-again answers.
type EntryAgainAnswer struct {
// the hand ask written
Asked EntryAgainAnswerAsked `json:"asked"`
// the verb that reads the status, first-views
Read string `json:"read"`
}
// ProcessBuildsInput is what process-builds takes.
type ProcessBuildsInput struct {
// only this module's processes
+6
View File
@@ -115,6 +115,12 @@ func TestFixtures(t *testing.T) {
decode: func(b []byte) (any, error) { var v ProcessBuildsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "first-view-again names the owner, its state and why", subject: "", given: "{\"owner\":\"mesh-delivery-indexer\",\"state\":\"manifests\",\"why\":\"the picture lags the indexer by hand\"}", wire: "{\"owner\":\"mesh-delivery-indexer\",\"state\":\"manifests\",\"why\":\"the picture lags the indexer by hand\"}",
decode: func(b []byte) (any, error) { var v FirstViewAgainInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "first-views answers its entries and its kept wants", subject: "", given: "{\"entries\":[{\"fingerprint\":\"b3f1c9\",\"since\":\"2026-11-11T08:00:00Z\",\"state\":\"asked\"},{\"fingerprint\":\"a77d02\",\"since\":\"2026-11-11T08:01:00Z\",\"state\":\"answered\"},{\"fingerprint\":\"0c1e55\",\"since\":\"2026-11-11T08:02:00Z\",\"state\":\"not-found\"}],\"first-views\":[],\"wants\":[{\"fingerprint\":\"b3f1c9\",\"kept-since\":\"2026-11-11T07:00:00Z\",\"module\":\"mesh-delivery-indexer\"}]}", wire: "{\"entries\":[{\"fingerprint\":\"b3f1c9\",\"since\":\"2026-11-11T08:00:00Z\",\"state\":\"asked\"},{\"fingerprint\":\"a77d02\",\"since\":\"2026-11-11T08:01:00Z\",\"state\":\"answered\"},{\"fingerprint\":\"0c1e55\",\"since\":\"2026-11-11T08:02:00Z\",\"state\":\"not-found\"}],\"first-views\":[],\"wants\":[{\"fingerprint\":\"b3f1c9\",\"kept-since\":\"2026-11-11T07:00:00Z\",\"module\":\"mesh-delivery-indexer\"}]}",
decode: func(b []byte) (any, error) { var v FirstViewsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "entry-again names the fingerprint and why", subject: "", given: "{\"fingerprint\":\"b3f1c9\",\"why\":\"the entry could not be read\"}", wire: "{\"fingerprint\":\"b3f1c9\",\"why\":\"the entry could not be read\"}",
decode: func(b []byte) (any, error) { var v EntryAgainInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "entry-again answers what was asked and where it is read", subject: "", given: "{\"asked\":{\"at\":\"2026-11-11T08:00:00Z\",\"by\":\"operator@shanks\",\"fingerprint\":\"b3f1c9\",\"v\":1,\"why\":\"the entry could not be read\"},\"read\":\"first-views\"}", wire: "{\"asked\":{\"at\":\"2026-11-11T08:00:00Z\",\"by\":\"operator@shanks\",\"fingerprint\":\"b3f1c9\",\"v\":1,\"why\":\"the entry could not be read\"},\"read\":\"first-views\"}",
decode: func(b []byte) (any, error) { var v EntryAgainAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))