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:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -165,5 +165,58 @@
|
||||
"state": "manifests",
|
||||
"why": "the picture lags the indexer by hand"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "first-views answers its entries and its kept wants",
|
||||
"of": "verb:first-views.answer",
|
||||
"given": {
|
||||
"first-views": [],
|
||||
"entries": [
|
||||
{
|
||||
"fingerprint": "b3f1c9",
|
||||
"state": "asked",
|
||||
"since": "2026-11-11T08:00:00Z"
|
||||
},
|
||||
{
|
||||
"fingerprint": "a77d02",
|
||||
"state": "answered",
|
||||
"since": "2026-11-11T08:01:00Z"
|
||||
},
|
||||
{
|
||||
"fingerprint": "0c1e55",
|
||||
"state": "not-found",
|
||||
"since": "2026-11-11T08:02:00Z"
|
||||
}
|
||||
],
|
||||
"wants": [
|
||||
{
|
||||
"module": "mesh-delivery-indexer",
|
||||
"fingerprint": "b3f1c9",
|
||||
"kept-since": "2026-11-11T07:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "entry-again names the fingerprint and why",
|
||||
"of": "verb:entry-again.input",
|
||||
"given": {
|
||||
"fingerprint": "b3f1c9",
|
||||
"why": "the entry could not be read"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "entry-again answers what was asked and where it is read",
|
||||
"of": "verb:entry-again.answer",
|
||||
"given": {
|
||||
"asked": {
|
||||
"v": 1,
|
||||
"fingerprint": "b3f1c9",
|
||||
"why": "the entry could not be read",
|
||||
"by": "operator@shanks",
|
||||
"at": "2026-11-11T08:00:00Z"
|
||||
},
|
||||
"read": "first-views"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+132
-2
@@ -715,7 +715,7 @@
|
||||
},
|
||||
{
|
||||
"name": "first-views",
|
||||
"description": "The node-engine's first views of the owners' states it follows (design 47 G 422, 204): per owner and state, the tool it asks, the revision its picture holds and why it is behind, when it asked and was answered, how many asks and whether its condition is raised; served by mesh-sdk's runtime as the view's read tool.",
|
||||
"description": "The node-engine's first views of the owners' states it follows (design 47 G 422, 204): per owner and state, the tool it asks, the revision its picture holds and why it is behind, when it asked and was answered, how many asks and whether its condition is raised; served by mesh-sdk's runtime as the view's read tool; its entries and its kept wants beside (design 47 G 698).",
|
||||
"class": "read",
|
||||
"input": {
|
||||
"type": "object",
|
||||
@@ -724,7 +724,9 @@
|
||||
"answer": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"first-views"
|
||||
"first-views",
|
||||
"entries",
|
||||
"wants"
|
||||
],
|
||||
"properties": {
|
||||
"first-views": {
|
||||
@@ -733,6 +735,65 @@
|
||||
"type": "object"
|
||||
},
|
||||
"description": "one status per owner and state followed, as mesh-sdk's views runtime keeps it"
|
||||
},
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"description": "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)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fingerprint",
|
||||
"state",
|
||||
"since"
|
||||
],
|
||||
"properties": {
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"description": "the build's fingerprint"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"asked",
|
||||
"answered",
|
||||
"not-found"
|
||||
],
|
||||
"description": "asked of the indexer, answered, or not found by it"
|
||||
},
|
||||
"since": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "since when it stands in that state, RFC 3339"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wants": {
|
||||
"type": "array",
|
||||
"description": "the wants the node-engine keeps (design 47 G 683, 698)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"module",
|
||||
"fingerprint",
|
||||
"kept-since"
|
||||
],
|
||||
"properties": {
|
||||
"module": {
|
||||
"type": "string",
|
||||
"description": "the module the want is of"
|
||||
},
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"description": "the fingerprint wanted"
|
||||
},
|
||||
"kept-since": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "since when the want is kept, RFC 3339"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -816,6 +877,75 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "entry-again",
|
||||
"description": "Ask the indexer's entry of a build again now, by hand (design 47 G 683, 698): a hand act, its caller and why kept; the answer says what was asked and the verb that reads it.",
|
||||
"class": "act",
|
||||
"input": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fingerprint",
|
||||
"why"
|
||||
],
|
||||
"properties": {
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"description": "the build's fingerprint, as first-views' entries name it"
|
||||
},
|
||||
"why": {
|
||||
"type": "string",
|
||||
"description": "why it is asked again, in plain words"
|
||||
}
|
||||
}
|
||||
},
|
||||
"answer": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"asked",
|
||||
"read"
|
||||
],
|
||||
"properties": {
|
||||
"asked": {
|
||||
"type": "object",
|
||||
"description": "the hand ask written",
|
||||
"required": [
|
||||
"v",
|
||||
"fingerprint",
|
||||
"why",
|
||||
"by",
|
||||
"at"
|
||||
],
|
||||
"properties": {
|
||||
"v": {
|
||||
"type": "integer",
|
||||
"description": "the layout's version"
|
||||
},
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"description": "the build's fingerprint"
|
||||
},
|
||||
"why": {
|
||||
"type": "string",
|
||||
"description": "why it was asked again"
|
||||
},
|
||||
"by": {
|
||||
"type": "string",
|
||||
"description": "the caller the runtime proved"
|
||||
},
|
||||
"at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "when it was asked, RFC 3339"
|
||||
}
|
||||
}
|
||||
},
|
||||
"read": {
|
||||
"type": "string",
|
||||
"description": "the verb that reads the status, first-views"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "process-builds",
|
||||
"description": "The build each process on this node was started with (design 47 *The revision view*): per service and container the fingerprint the node-engine handed it in MESH_FINGERPRINT, or why it is unknown, and when it started. Narrowed by module. Reads only.",
|
||||
|
||||
Vendored
+53
@@ -20,6 +20,7 @@ export declare const verbs: {
|
||||
readonly seatListAgain: "seat-list-again";
|
||||
readonly firstViews: "first-views";
|
||||
readonly firstViewAgain: "first-view-again";
|
||||
readonly entryAgain: "entry-again";
|
||||
readonly processBuilds: "process-builds";
|
||||
};
|
||||
|
||||
@@ -1021,10 +1022,32 @@ export type SeatListAgainAnswer = SeatList;
|
||||
export interface FirstViewsInput {
|
||||
}
|
||||
|
||||
export interface FirstViewsAnswerEntriesItem {
|
||||
/** the build's fingerprint */
|
||||
"fingerprint": string;
|
||||
/** since when it stands in that state, RFC 3339 */
|
||||
"since": string;
|
||||
/** asked of the indexer, answered, or not found by it */
|
||||
"state": "asked" | "answered" | "not-found";
|
||||
}
|
||||
|
||||
export interface FirstViewsAnswerWantsItem {
|
||||
/** the fingerprint wanted */
|
||||
"fingerprint": string;
|
||||
/** since when the want is kept, RFC 3339 */
|
||||
"kept-since": string;
|
||||
/** the module the want is of */
|
||||
"module": string;
|
||||
}
|
||||
|
||||
/** is what first-views answers. */
|
||||
export interface FirstViewsAnswer {
|
||||
/** 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[];
|
||||
/** one status per owner and state followed, as mesh-sdk's views runtime keeps it */
|
||||
"first-views": Record<string, unknown>[];
|
||||
/** the wants the node-engine keeps (design 47 G 683, 698) */
|
||||
"wants": FirstViewsAnswerWantsItem[];
|
||||
}
|
||||
|
||||
/** is what first-view-again takes. */
|
||||
@@ -1061,6 +1084,36 @@ export interface FirstViewAgainAnswer {
|
||||
"read": string;
|
||||
}
|
||||
|
||||
/** is what entry-again takes. */
|
||||
export interface EntryAgainInput {
|
||||
/** the build's fingerprint, as first-views' entries name it */
|
||||
"fingerprint": string;
|
||||
/** why it is asked again, in plain words */
|
||||
"why": string;
|
||||
}
|
||||
|
||||
/** the hand ask written */
|
||||
export interface EntryAgainAnswerAsked {
|
||||
/** when it was asked, RFC 3339 */
|
||||
"at": string;
|
||||
/** the caller the runtime proved */
|
||||
"by": string;
|
||||
/** the build's fingerprint */
|
||||
"fingerprint": string;
|
||||
/** the layout's version */
|
||||
"v": number;
|
||||
/** why it was asked again */
|
||||
"why": string;
|
||||
}
|
||||
|
||||
/** is what entry-again answers. */
|
||||
export interface EntryAgainAnswer {
|
||||
/** the hand ask written */
|
||||
"asked": EntryAgainAnswerAsked;
|
||||
/** the verb that reads the status, first-views */
|
||||
"read": string;
|
||||
}
|
||||
|
||||
/** is what process-builds takes. */
|
||||
export interface ProcessBuildsInput {
|
||||
/** only this module's processes */
|
||||
|
||||
@@ -20,6 +20,7 @@ export const verbs = {
|
||||
seatListAgain: "seat-list-again",
|
||||
firstViews: "first-views",
|
||||
firstViewAgain: "first-view-again",
|
||||
entryAgain: "entry-again",
|
||||
processBuilds: "process-builds",
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user