The node-engine seat whole: every verb's answer, its events' bodies, and ADR 0618's manifest-reads and manifest-reads-changed
The seat's area changes in this milestone, so it moves whole into its contracts (ADR 0613 §3): the eleven verbs it serves get their answers as the engine writes them, asked, done and refused their body, and the seat serves the optional verb manifest-reads (ADR 0618 §3) and says manifest-reads-changed (§4). Each event is published per node, the node's name its last token (by-caller), and kept with the seat's events for seven days. compose-candidate's input is a boolean, as the engine and the checker read it. Fixtures for every event, compose-candidate's input and three answers. Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
This commit is contained in:
@@ -0,0 +1,554 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
// Package nodeengine is the contract of the seat "node-engine", defined whole (seats/node-engine/seat.json): The node seat every node's engine holds (novox/hq ADR 0563, ADR 0618 §3, §4): its hand acts on the operator's warrant, its read-only judgements, its compositions and what it reads of a manifest. Each verb is answered on this node's subject, mesh.seat.node-engine.tool.<verb>.<node>, and each event is published on mesh.seat.node-engine.event.<event>.<node>, the node's name its last token.
|
||||
package nodeengine
|
||||
|
||||
// Seat is the seat's name.
|
||||
const Seat = "node-engine"
|
||||
|
||||
const (
|
||||
VerbHandOver = "hand-over"
|
||||
VerbAccessAct = "access-act"
|
||||
VerbJudgeDirectories = "judge-directories"
|
||||
VerbSetuidSearch = "setuid-search"
|
||||
VerbRootFree = "root-free"
|
||||
VerbActs = "acts"
|
||||
VerbPackages = "packages"
|
||||
VerbComposition = "composition"
|
||||
VerbCompose = "compose"
|
||||
VerbComposeCandidate = "compose-candidate"
|
||||
VerbPullWaits = "pull-waits"
|
||||
VerbManifestReads = "manifest-reads"
|
||||
)
|
||||
|
||||
const (
|
||||
EventAsked = "asked"
|
||||
EventDone = "done"
|
||||
EventRefused = "refused"
|
||||
EventManifestReadsChanged = "manifest-reads-changed"
|
||||
)
|
||||
|
||||
// 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, VerbPullWaits, VerbManifestReads}
|
||||
}
|
||||
|
||||
// Events is every event published on the seat's subject: a new copy each call.
|
||||
func Events() []string {
|
||||
return []string{EventAsked, EventDone, EventRefused, EventManifestReadsChanged}
|
||||
}
|
||||
|
||||
// Family is where the seat's events are kept.
|
||||
const (
|
||||
Family = "node-engine.events"
|
||||
FamilyMaxAgeDays = 7
|
||||
)
|
||||
|
||||
// SubjectAsked is where asked is published for one caller.
|
||||
func SubjectAsked(caller string) string { return "mesh.seat.node-engine.event.asked." + caller }
|
||||
|
||||
// SubjectDone is where done is published for one caller.
|
||||
func SubjectDone(caller string) string { return "mesh.seat.node-engine.event.done." + caller }
|
||||
|
||||
// SubjectRefused is where refused is published for one caller.
|
||||
func SubjectRefused(caller string) string { return "mesh.seat.node-engine.event.refused." + caller }
|
||||
|
||||
// SubjectManifestReadsChanged is where manifest-reads-changed is published for one caller.
|
||||
func SubjectManifestReadsChanged(caller string) string {
|
||||
return "mesh.seat.node-engine.event.manifest-reads-changed." + caller
|
||||
}
|
||||
|
||||
// Act is one act asked through the seat, as acts reads it (ADR 0563 §9).
|
||||
type Act struct {
|
||||
// the act: hand-over, access-act, judge-directories or setuid-search
|
||||
Act string `json:"act"`
|
||||
// the operator's ask of a hand-over or an access act
|
||||
Ask string `json:"ask,omitempty"`
|
||||
// when it was asked, RFC 3339
|
||||
At string `json:"at"`
|
||||
// the engine asked it itself, on finding a library's root holding data outside its group (ADR 0563 §4)
|
||||
Auto bool `json:"auto,omitempty"`
|
||||
// who answered, as the operator's warrant names them
|
||||
By string `json:"by,omitempty"`
|
||||
// the caller as the runtime proved it
|
||||
Caller string `json:"caller"`
|
||||
// what the engine read on disk when it judged
|
||||
Disk string `json:"disk,omitempty"`
|
||||
// when it ended, RFC 3339
|
||||
Ended string `json:"ended,omitempty"`
|
||||
// when the ask ends unanswered, RFC 3339
|
||||
Expires string `json:"expires,omitempty"`
|
||||
// the act's id
|
||||
ID string `json:"id"`
|
||||
// the directory the act changes
|
||||
Path string `json:"path,omitempty"`
|
||||
// the warrant's proofs
|
||||
Proofs []string `json:"proofs,omitempty"`
|
||||
// what the engine said of it: its outcome or why it was refused
|
||||
Said string `json:"said,omitempty"`
|
||||
// the owner, group and mode it sets, in words
|
||||
Sets string `json:"sets,omitempty"`
|
||||
// where it stands
|
||||
State string `json:"state"`
|
||||
// the path of a hand-over, or the access of an access act
|
||||
Subject string `json:"subject,omitempty"`
|
||||
// the channel the warrant came on
|
||||
Via string `json:"via,omitempty"`
|
||||
// why it was asked, in words
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
// ActSaid is what the seat says of an act: the act, the path or access, the caller as the runtime proved it and the ask (ADR 0563 §1).
|
||||
type ActSaid struct {
|
||||
// the act
|
||||
Act string `json:"act"`
|
||||
// the operator's ask
|
||||
Ask string `json:"ask,omitempty"`
|
||||
// the caller as the runtime proved it
|
||||
Caller string `json:"caller"`
|
||||
// the node whose engine says it
|
||||
Node string `json:"node"`
|
||||
// what the engine said of it
|
||||
Said string `json:"said,omitempty"`
|
||||
// where the act stands
|
||||
State string `json:"state"`
|
||||
// the path or the access
|
||||
Subject string `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
// Acts is the acts kept.
|
||||
type Acts struct {
|
||||
// the acts, newest first
|
||||
Acts []Act `json:"acts"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
}
|
||||
|
||||
// Asked is the answer of an act the operator is asked.
|
||||
type Asked struct {
|
||||
// the ask's id: acts shows where it stands
|
||||
Asked string `json:"asked"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// what happens next, in words
|
||||
Says string `json:"says"`
|
||||
}
|
||||
|
||||
// ManifestReadsChanged is what a node-engine says when what it reads changed or its node returned (ADR 0618 §4).
|
||||
type ManifestReadsChanged struct {
|
||||
// when it says it, RFC 3339
|
||||
At string `json:"at"`
|
||||
// what its engine states it reads now
|
||||
ManifestReads []string `json:"manifest-reads,omitempty"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// the layout's version
|
||||
V int64 `json:"v"`
|
||||
// started: the engine started or what it states changed; returned: its node returned after being away
|
||||
Why string `json:"why"`
|
||||
}
|
||||
|
||||
// Module is one module's composition with the candidate.
|
||||
type Module struct {
|
||||
// the candidate changes it from the one composed without it
|
||||
Changed bool `json:"changed,omitempty"`
|
||||
// the composition's digest when composed
|
||||
Digest string `json:"digest,omitempty"`
|
||||
// the fingerprint it was composed at
|
||||
Fp string `json:"fp,omitempty"`
|
||||
// the module, node for the node's own composition
|
||||
Module string `json:"module"`
|
||||
// composed (digest set), refused by the candidate, or held without it too (words set)
|
||||
State string `json:"state"`
|
||||
// why, for a refused or held one
|
||||
Words string `json:"words,omitempty"`
|
||||
}
|
||||
|
||||
// Revision is one revision of a composition key.
|
||||
type Revision struct {
|
||||
// its digest
|
||||
Digest string `json:"digest,omitempty"`
|
||||
// the composition's key
|
||||
Key string `json:"key"`
|
||||
// the latest revision
|
||||
Latest bool `json:"latest,omitempty"`
|
||||
// why it cannot be read or trusted
|
||||
Refused string `json:"refused,omitempty"`
|
||||
// how many resources it names
|
||||
Resources int64 `json:"resources,omitempty"`
|
||||
// its revision
|
||||
Revision int64 `json:"revision,omitempty"`
|
||||
}
|
||||
|
||||
// RootVerdict is the engine's root-free verdict (ADR 0563 §6).
|
||||
type RootVerdict struct {
|
||||
// the machine is root-free
|
||||
Free bool `json:"free"`
|
||||
// when the engine judged it, RFC 3339
|
||||
Judged string `json:"judged"`
|
||||
// the machine
|
||||
Machine string `json:"machine"`
|
||||
// why, in words
|
||||
Why string `json:"why"`
|
||||
}
|
||||
|
||||
// Said is the answer of a read-only judgement.
|
||||
type Said struct {
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// the engine's judgement or search, one line per directory or program
|
||||
Said string `json:"said"`
|
||||
}
|
||||
|
||||
// HandOverInput is what hand-over takes.
|
||||
type HandOverInput struct {
|
||||
// the directory's absolute path, as the engine states it
|
||||
Path string `json:"path"`
|
||||
// why it is asked, in words the operator reads
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
// HandOverAnswer is what hand-over answers.
|
||||
type HandOverAnswer = Asked
|
||||
|
||||
// AccessActInput is what access-act takes.
|
||||
type AccessActInput struct {
|
||||
// the access, library:<name>
|
||||
Access string `json:"access"`
|
||||
// the act: take
|
||||
Act string `json:"act"`
|
||||
// why it is asked, in words the operator reads
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
// AccessActAnswer is what access-act answers.
|
||||
type AccessActAnswer = Asked
|
||||
|
||||
// JudgeDirectoriesInput is what judge-directories takes.
|
||||
type JudgeDirectoriesInput struct {
|
||||
}
|
||||
|
||||
// JudgeDirectoriesAnswer is what judge-directories answers.
|
||||
type JudgeDirectoriesAnswer = Said
|
||||
|
||||
// SetuidSearchInput is what setuid-search takes.
|
||||
type SetuidSearchInput struct {
|
||||
// why it is asked, in words
|
||||
Why string `json:"why,omitempty"`
|
||||
}
|
||||
|
||||
// SetuidSearchAnswer is what setuid-search answers.
|
||||
type SetuidSearchAnswer = Said
|
||||
|
||||
// RootFreeInput is what root-free takes.
|
||||
type RootFreeInput struct {
|
||||
}
|
||||
|
||||
// RootFreeAnswer is what root-free answers.
|
||||
type RootFreeAnswer struct {
|
||||
// this machine's verdict
|
||||
Machines []RootVerdict `json:"machines"`
|
||||
}
|
||||
|
||||
// ActsInput is what acts takes.
|
||||
type ActsInput struct {
|
||||
// one act, by its id
|
||||
ID string `json:"id,omitempty"`
|
||||
// at most this many, newest
|
||||
Limit string `json:"limit,omitempty"`
|
||||
}
|
||||
|
||||
// ActsAnswer is what acts answers.
|
||||
type ActsAnswer = Acts
|
||||
|
||||
// PackagesInput is what packages takes.
|
||||
type PackagesInput struct {
|
||||
// "true": write this machine's key again from what the engine composed
|
||||
Write string `json:"write,omitempty"`
|
||||
}
|
||||
|
||||
// PackagesAnswerKeyPackagesItem is a type of the contract.
|
||||
type PackagesAnswerKeyPackagesItem struct {
|
||||
// declared absent
|
||||
Absent bool `json:"absent"`
|
||||
// the modules that declare it
|
||||
Modules []string `json:"modules"`
|
||||
// the package
|
||||
Package string `json:"package"`
|
||||
}
|
||||
|
||||
// PackagesAnswerKey is the node's key as the bus holds it; absent when the engine wrote none.
|
||||
type PackagesAnswerKey struct {
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// its packages sorted by name, absent after present
|
||||
Packages []PackagesAnswerKeyPackagesItem `json:"packages"`
|
||||
}
|
||||
|
||||
// PackagesAnswer is what packages answers.
|
||||
type PackagesAnswer struct {
|
||||
// the node's key as the bus holds it; absent when the engine wrote none
|
||||
Key *PackagesAnswerKey `json:"key,omitempty"`
|
||||
// why the key could not be read
|
||||
KeyError string `json:"key_error,omitempty"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// a note, such as that no key is written yet
|
||||
Note string `json:"note,omitempty"`
|
||||
// where the key is read: the engine's state packages
|
||||
Source string `json:"source"`
|
||||
// with write: the key was written again (false: it already held what the engine composed)
|
||||
Wrote bool `json:"wrote,omitempty"`
|
||||
}
|
||||
|
||||
// CompositionInput is what composition takes.
|
||||
type CompositionInput struct {
|
||||
// "true": list the resources that differ from what runs
|
||||
Diff string `json:"diff,omitempty"`
|
||||
// a composition's digest (sha256:…), to read that revision rather than the latest
|
||||
Digest string `json:"digest,omitempty"`
|
||||
// the module, as placed on this machine; node for the node's own
|
||||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
// CompositionAnswerAttempt is the module's last apply that did not end running; absent when none.
|
||||
type CompositionAnswerAttempt struct {
|
||||
// the want's revision the hold took
|
||||
AnsweredRevision int64 `json:"answered_revision,omitempty"`
|
||||
// the digest tried
|
||||
Composed string `json:"composed,omitempty"`
|
||||
// the composition's revision it was tried at
|
||||
CompositionRevision int64 `json:"composition_revision"`
|
||||
// the fingerprint tried
|
||||
Fp string `json:"fp"`
|
||||
// held for a failed backup
|
||||
Held bool `json:"held,omitempty"`
|
||||
// it failed because the bus did not answer for a moment
|
||||
Transient bool `json:"transient,omitempty"`
|
||||
// the want's revision it was tried at
|
||||
WantRevision int64 `json:"want_revision"`
|
||||
}
|
||||
|
||||
// CompositionAnswerHave is what the module's have key says now; absent when it says nothing.
|
||||
type CompositionAnswerHave struct {
|
||||
// digest
|
||||
Composed string `json:"composed,omitempty"`
|
||||
// detail
|
||||
Detail string `json:"detail,omitempty"`
|
||||
// fingerprint
|
||||
Fp string `json:"fp,omitempty"`
|
||||
// judgement
|
||||
Judgement string `json:"judgement,omitempty"`
|
||||
// running, failed, held or waiting-yes
|
||||
Phase string `json:"phase"`
|
||||
// the digest that waits for a yes
|
||||
Waits string `json:"waits,omitempty"`
|
||||
}
|
||||
|
||||
// CompositionAnswerJudged is the move from what runs to the composition read.
|
||||
type CompositionAnswerJudged struct {
|
||||
// the judgement
|
||||
Judgement string `json:"judgement"`
|
||||
// the agent would wait for a person's yes before applying it
|
||||
WaitsForYes bool `json:"waits_for_yes"`
|
||||
// its words
|
||||
Words string `json:"words"`
|
||||
}
|
||||
|
||||
// CompositionAnswerOwn is of the node's own composition, its own fields beside what runs names.
|
||||
type CompositionAnswerOwn struct {
|
||||
// the revision's adoption; absent for a converged node
|
||||
Adoption map[string]any `json:"adoption,omitempty"`
|
||||
// groups
|
||||
Groups int64 `json:"groups,omitempty"`
|
||||
// each module the node's composer held in its last pass, with why
|
||||
Held map[string]string `json:"held,omitempty"`
|
||||
// identities the revision names
|
||||
Identities int64 `json:"identities,omitempty"`
|
||||
// libraries
|
||||
Libraries int64 `json:"libraries,omitempty"`
|
||||
// the account the provisioner's client runs as, as the revision names it
|
||||
ProvisionerAccount string `json:"provisioner_account"`
|
||||
// as what runs names it
|
||||
RunsProvisionerAccount string `json:"runs_provisioner_account,omitempty"`
|
||||
}
|
||||
|
||||
// CompositionAnswerRuns is what runs of the module; absent when nothing runs.
|
||||
type CompositionAnswerRuns struct {
|
||||
// digest
|
||||
Composed string `json:"composed,omitempty"`
|
||||
// fingerprint
|
||||
Fp string `json:"fp,omitempty"`
|
||||
// applied, have or kept
|
||||
From string `json:"from"`
|
||||
// phase
|
||||
Phase string `json:"phase,omitempty"`
|
||||
// how many resources run
|
||||
Resources int64 `json:"resources"`
|
||||
}
|
||||
|
||||
// CompositionAnswerWant is the module's want as the agent holds it; absent when it holds none.
|
||||
type CompositionAnswerWant struct {
|
||||
// the operator's answer to a failed backup, again or skip
|
||||
Backup string `json:"backup,omitempty"`
|
||||
// the composition's digest it names
|
||||
Composed string `json:"composed,omitempty"`
|
||||
// its build's fingerprint
|
||||
Fp string `json:"fp"`
|
||||
// the module is removed
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
// the revision of the want's key read last
|
||||
Revision int64 `json:"revision"`
|
||||
// the node composes the module itself (ADR 0547 §2)
|
||||
Self bool `json:"self,omitempty"`
|
||||
// its words
|
||||
Words string `json:"words,omitempty"`
|
||||
// the digest a person said yes to
|
||||
Yes string `json:"yes,omitempty"`
|
||||
}
|
||||
|
||||
// CompositionAnswer is what composition answers.
|
||||
type CompositionAnswer struct {
|
||||
// the module's last apply that did not end running; absent when none
|
||||
Attempt *CompositionAnswerAttempt `json:"attempt,omitempty"`
|
||||
Composition Revision `json:"composition"`
|
||||
// every resource that differs from what runs, when asked
|
||||
Diff []map[string]any `json:"diff,omitempty"`
|
||||
// what the module's have key says now; absent when it says nothing
|
||||
Have *CompositionAnswerHave `json:"have,omitempty"`
|
||||
// the move from what runs to the composition read
|
||||
Judged CompositionAnswerJudged `json:"judged"`
|
||||
// the module
|
||||
Module string `json:"module"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// of the node's own composition, its own fields beside what runs names
|
||||
Own *CompositionAnswerOwn `json:"own,omitempty"`
|
||||
// the revisions of its key the bucket keeps, oldest first
|
||||
Revisions []Revision `json:"revisions,omitempty"`
|
||||
// what runs of the module; absent when nothing runs
|
||||
Runs *CompositionAnswerRuns `json:"runs,omitempty"`
|
||||
// the agent has looked at the module once since it started
|
||||
Started bool `json:"started"`
|
||||
// the module's want as the agent holds it; absent when it holds none
|
||||
Want *CompositionAnswerWant `json:"want,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeInput is what compose takes.
|
||||
type ComposeInput struct {
|
||||
// a module placed on this machine whose apply is also tried again (optional)
|
||||
Module string `json:"module,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeAnswerPass is how the pass went.
|
||||
type ComposeAnswerPass struct {
|
||||
// when the node composes again on its own, RFC 3339
|
||||
Again string `json:"again,omitempty"`
|
||||
// when the pass ended, RFC 3339
|
||||
At string `json:"at"`
|
||||
// the answer is the last pass, made moments ago
|
||||
Earlier bool `json:"earlier,omitempty"`
|
||||
// how many compositions the pass handed the agent that differ from before
|
||||
Handed int64 `json:"handed"`
|
||||
// each module refused alone, with why
|
||||
Held map[string]string `json:"held,omitempty"`
|
||||
// why the node composed none of its modules
|
||||
Refused string `json:"refused,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeAnswer is what compose answers.
|
||||
type ComposeAnswer struct {
|
||||
// how the pass went
|
||||
Pass ComposeAnswerPass `json:"pass"`
|
||||
// the module whose apply was tried again
|
||||
Retried string `json:"retried,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeCandidateInput is what compose-candidate takes.
|
||||
type ComposeCandidateInput struct {
|
||||
// the key of the indexer's candidate, <group>.<heads hash>
|
||||
Candidate string `json:"candidate"`
|
||||
// also answer the composition input the candidate was composed from, for the sandbox path
|
||||
Input bool `json:"input,omitempty"`
|
||||
}
|
||||
|
||||
// ComposeCandidateAnswer is what compose-candidate answers.
|
||||
type ComposeCandidateAnswer struct {
|
||||
// the candidate's key
|
||||
Candidate string `json:"candidate"`
|
||||
// when asked: the composition input it composed from
|
||||
Input map[string]any `json:"input,omitempty"`
|
||||
// every module placed on the node, sorted by name
|
||||
Modules []Module `json:"modules"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
Own Module `json:"own"`
|
||||
// why the node could not compose with the candidate at all
|
||||
Refused string `json:"refused,omitempty"`
|
||||
// how long the engine took, in milliseconds
|
||||
Took int64 `json:"took"`
|
||||
// the layout's version
|
||||
V int64 `json:"v"`
|
||||
// the node's verdict (ADR 0593 §7, §9)
|
||||
Verdict string `json:"verdict"`
|
||||
}
|
||||
|
||||
// PullWaitsInput is what pull-waits takes.
|
||||
type PullWaitsInput struct {
|
||||
}
|
||||
|
||||
// PullWaitsAnswerWaitsItem is a type of the contract.
|
||||
type PullWaitsAnswerWaitsItem struct {
|
||||
// that seat's holder, whose settled the retry waits on
|
||||
Holder string `json:"holder,omitempty"`
|
||||
// the image whose pull failed
|
||||
Image string `json:"image"`
|
||||
// the module whose apply failed
|
||||
Module string `json:"module"`
|
||||
// when the failed pull began, RFC 3339
|
||||
PullBegan string `json:"pull-began,omitempty"`
|
||||
// when it was last tried again, RFC 3339
|
||||
RetryLast string `json:"retry-last,omitempty"`
|
||||
// what started that retry: settled, or the engine's start
|
||||
RetryTrigger string `json:"retry-trigger,omitempty"`
|
||||
// the seat the image came through
|
||||
Seat string `json:"seat,omitempty"`
|
||||
// the settled events of the holder heard since the engine started
|
||||
SettledCount int64 `json:"settled-count,omitempty"`
|
||||
// when the last was heard, RFC 3339
|
||||
SettledLast string `json:"settled-last,omitempty"`
|
||||
}
|
||||
|
||||
// PullWaitsAnswer is what pull-waits answers.
|
||||
type PullWaitsAnswer struct {
|
||||
// every failed pull waiting on a holder
|
||||
Waits []PullWaitsAnswerWaitsItem `json:"waits"`
|
||||
}
|
||||
|
||||
// ManifestReadsInput is what manifest-reads takes.
|
||||
type ManifestReadsInput struct {
|
||||
}
|
||||
|
||||
// ManifestReadsAnswer is what manifest-reads answers.
|
||||
type ManifestReadsAnswer struct {
|
||||
// the reader capabilities its engine states: the manifest words, forms and seat names it reads; empty for an engine built before it said them, read as the baseline
|
||||
ManifestReads []string `json:"manifest-reads,omitempty"`
|
||||
// the node
|
||||
Node string `json:"node"`
|
||||
// when the engine last stated them, RFC 3339
|
||||
StatedAt string `json:"stated-at"`
|
||||
// the layout's version
|
||||
V int64 `json:"v"`
|
||||
}
|
||||
|
||||
// AskedEvent is the body of the event asked.
|
||||
type AskedEvent = ActSaid
|
||||
|
||||
// DoneEvent is the body of the event done.
|
||||
type DoneEvent = ActSaid
|
||||
|
||||
// RefusedEvent is the body of the event refused.
|
||||
type RefusedEvent = ActSaid
|
||||
|
||||
// ManifestReadsChangedEvent is the body of the event manifest-reads-changed.
|
||||
type ManifestReadsChangedEvent = ManifestReadsChanged
|
||||
@@ -0,0 +1,74 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
package nodeengine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestFixtures reads every fixture of seats/node-engine/fixtures: each decodes into its type, a field the type does not
|
||||
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
|
||||
func TestFixtures(t *testing.T) {
|
||||
cases := []struct {
|
||||
name, subject, given, wire string
|
||||
decode func([]byte) (any, error)
|
||||
subjectIs *regexp.Regexp
|
||||
}{
|
||||
{name: "asked on the node's subject", subject: "mesh.seat.node-engine.event.asked.ace", given: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"state\":\"asked\",\"subject\":\"/srv/media\"}", wire: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"state\":\"asked\",\"subject\":\"/srv/media\"}",
|
||||
decode: func(b []byte) (any, error) { var v AskedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.asked\\.[A-Za-z0-9_-]+$")},
|
||||
{name: "done on the node's subject", subject: "mesh.seat.node-engine.event.done.ace", given: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"handed over: owner media, group media, mode 2775\",\"state\":\"done\",\"subject\":\"/srv/media\"}", wire: "{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"handed over: owner media, group media, mode 2775\",\"state\":\"done\",\"subject\":\"/srv/media\"}",
|
||||
decode: func(b []byte) (any, error) { var v DoneEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.done\\.[A-Za-z0-9_-]+$")},
|
||||
{name: "refused on the node's subject", subject: "mesh.seat.node-engine.event.refused.ace", given: "{\"act\":\"access-act\",\"ask\":\"access-act-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"the operator said no\",\"state\":\"refused\",\"subject\":\"library:music\"}", wire: "{\"act\":\"access-act\",\"ask\":\"access-act-1\",\"caller\":\"mesh-tools\",\"node\":\"ace\",\"said\":\"the operator said no\",\"state\":\"refused\",\"subject\":\"library:music\"}",
|
||||
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.refused\\.[A-Za-z0-9_-]+$")},
|
||||
{name: "manifest-reads-changed when the engine started", subject: "mesh.seat.node-engine.event.manifest-reads-changed.ace", given: "{\"at\":\"2026-11-04T10:00:00Z\",\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"v\":1,\"why\":\"started\"}", wire: "{\"at\":\"2026-11-04T10:00:00Z\",\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"v\":1,\"why\":\"started\"}",
|
||||
decode: func(b []byte) (any, error) {
|
||||
var v ManifestReadsChangedEvent
|
||||
err := json.Unmarshal(b, &v)
|
||||
return v, err
|
||||
}, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.manifest-reads-changed\\.[A-Za-z0-9_-]+$")},
|
||||
{name: "manifest-reads-changed when the node returned, from an engine that states none", subject: "mesh.seat.node-engine.event.manifest-reads-changed.g14", given: "{\"at\":\"2026-11-04T10:05:00Z\",\"node\":\"g14\",\"v\":1,\"why\":\"returned\"}", wire: "{\"at\":\"2026-11-04T10:05:00Z\",\"node\":\"g14\",\"v\":1,\"why\":\"returned\"}",
|
||||
decode: func(b []byte) (any, error) {
|
||||
var v ManifestReadsChangedEvent
|
||||
err := json.Unmarshal(b, &v)
|
||||
return v, err
|
||||
}, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-engine\\.event\\.manifest-reads-changed\\.[A-Za-z0-9_-]+$")},
|
||||
{name: "manifest-reads answers what the engine reads and when it stated it", subject: "", given: "{\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"stated-at\":\"2026-11-04T10:00:00Z\",\"v\":1}", wire: "{\"manifest-reads\":[\"form:seat-reference\",\"word:series\"],\"node\":\"ace\",\"stated-at\":\"2026-11-04T10:00:00Z\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v ManifestReadsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "manifest-reads of an engine built before it said them is the baseline", subject: "", given: "{\"node\":\"g14\",\"stated-at\":\"2026-11-04T10:05:00Z\",\"v\":1}", wire: "{\"node\":\"g14\",\"stated-at\":\"2026-11-04T10:05:00Z\",\"v\":1}",
|
||||
decode: func(b []byte) (any, error) { var v ManifestReadsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "compose-candidate asks the candidate and, as a boolean, its composition input", subject: "", given: "{\"candidate\":\"mesh-host.0123abcd\",\"input\":true}", wire: "{\"candidate\":\"mesh-host.0123abcd\",\"input\":true}",
|
||||
decode: func(b []byte) (any, error) { var v ComposeCandidateInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "compose-candidate answers per module and the node's own", subject: "", given: "{\"candidate\":\"mesh-host.0123abcd\",\"modules\":[{\"changed\":true,\"digest\":\"sha256:aa\",\"fp\":\"fp-1\",\"module\":\"plex\",\"state\":\"composed\"}],\"node\":\"ace\",\"own\":{\"digest\":\"sha256:bb\",\"module\":\"node\",\"state\":\"composed\"},\"took\":1200,\"v\":1,\"verdict\":\"composed\"}", wire: "{\"candidate\":\"mesh-host.0123abcd\",\"modules\":[{\"changed\":true,\"digest\":\"sha256:aa\",\"fp\":\"fp-1\",\"module\":\"plex\",\"state\":\"composed\"}],\"node\":\"ace\",\"own\":{\"digest\":\"sha256:bb\",\"module\":\"node\",\"state\":\"composed\"},\"took\":1200,\"v\":1,\"verdict\":\"composed\"}",
|
||||
decode: func(b []byte) (any, error) { var v ComposeCandidateAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
{name: "acts answers each act kept", subject: "", given: "{\"acts\":[{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"at\":\"2026-11-04T09:00:00Z\",\"caller\":\"mesh-tools\",\"expires\":\"2026-11-05T09:00:00Z\",\"id\":\"hand-over-1\",\"state\":\"asked\",\"subject\":\"/srv/media\"}],\"node\":\"ace\"}", wire: "{\"acts\":[{\"act\":\"hand-over\",\"ask\":\"hand-over-1\",\"at\":\"2026-11-04T09:00:00Z\",\"caller\":\"mesh-tools\",\"expires\":\"2026-11-05T09:00:00Z\",\"id\":\"hand-over-1\",\"state\":\"asked\",\"subject\":\"/srv/media\"}],\"node\":\"ace\"}",
|
||||
decode: func(b []byte) (any, error) { var v ActsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
|
||||
}
|
||||
for _, c := range cases {
|
||||
v, err := c.decode([]byte(c.given))
|
||||
if err != nil {
|
||||
t.Errorf("%s: does not decode: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
back, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Errorf("%s: does not encode: %v", c.name, err)
|
||||
continue
|
||||
}
|
||||
var got, want any
|
||||
if err := json.Unmarshal(back, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
|
||||
}
|
||||
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
|
||||
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user