§717 (1): the status view's answers are a view of the seat mesh-delivery-view
The Delivery contracts module defines the seat mesh-delivery-view (scope mesh, grain whole, ADR 0540): no verb, no seat event, no family, one state answers (template state, history 5, view), one key form per kind of mesh-wants' asks with .view after it (A-299), its value the answer (v, asking, option, words); seatgen writes its Go and TypeScript packages, and the module's artifacts name them. The status view claims the seat (scope mesh, serves none), its first-view tool answers (views.FirstViewTool, callers the teller, A-301) replaces view_read_answers, and it deletes its answer once the ask's key has left asks. The teller follows the answers by seat:mesh-delivery-view.views.answers and invokes nothing of the view's. Builds: design 47 G §717, A-299, A-301 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
// Package meshdeliveryview is the contract of the seat "mesh-delivery-view", defined whole (seats/mesh-delivery-view/seat.json): The status view of deliveries (ADR 0540): it serves no verb and says no seat event; its tools and its events delivered, moving, settled and stuck stay its holder's own, and it keeps the person's answers given in the web view.
|
||||
package meshdeliveryview
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Seat is the seat's name.
|
||||
const Seat = "mesh-delivery-view"
|
||||
|
||||
const (
|
||||
StateAnswers = "answers"
|
||||
)
|
||||
|
||||
// AnswersByHoldModuleFingerprintViewKey is the key of one value of the state answers under the form "hold.<module>.<fingerprint>.view".
|
||||
func AnswersByHoldModuleFingerprintViewKey(module, fingerprint string) string {
|
||||
return "hold." + module + "." + fingerprint + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByHoldModuleFingerprintViewKey reads the parts of a key of the form "hold.<module>.<fingerprint>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByHoldModuleFingerprintViewKey(key string) (string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "hold.") {
|
||||
return "", "", false
|
||||
}
|
||||
rest = rest[5:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".view")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", false
|
||||
}
|
||||
rest = after3
|
||||
if rest != "" {
|
||||
return "", "", false
|
||||
}
|
||||
return v1, v3, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByHoldModuleFingerprintViewValue reads one value of the state answers under the form "hold.<module>.<fingerprint>.view", refusing a field AnswersByHoldModuleFingerprintViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByHoldModuleFingerprintViewValue(raw []byte) (AnswersByHoldModuleFingerprintViewValue, error) {
|
||||
var v AnswersByHoldModuleFingerprintViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByRestoreNodeModuleFingerprintViewKey is the key of one value of the state answers under the form "restore.<node>.<module>.<fingerprint>.view".
|
||||
func AnswersByRestoreNodeModuleFingerprintViewKey(node, module, fingerprint string) string {
|
||||
return "restore." + node + "." + module + "." + fingerprint + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByRestoreNodeModuleFingerprintViewKey reads the parts of a key of the form "restore.<node>.<module>.<fingerprint>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByRestoreNodeModuleFingerprintViewKey(key string) (string, string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "restore.") {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = rest[8:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after3
|
||||
v5, after5, found5 := strings.Cut(rest, ".view")
|
||||
if !found5 || v5 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after5
|
||||
if rest != "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
return v1, v3, v5, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByRestoreNodeModuleFingerprintViewValue reads one value of the state answers under the form "restore.<node>.<module>.<fingerprint>.view", refusing a field AnswersByRestoreNodeModuleFingerprintViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByRestoreNodeModuleFingerprintViewValue(raw []byte) (AnswersByRestoreNodeModuleFingerprintViewValue, error) {
|
||||
var v AnswersByRestoreNodeModuleFingerprintViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByBackupNodeModuleFingerprintViewKey is the key of one value of the state answers under the form "backup.<node>.<module>.<fingerprint>.view".
|
||||
func AnswersByBackupNodeModuleFingerprintViewKey(node, module, fingerprint string) string {
|
||||
return "backup." + node + "." + module + "." + fingerprint + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByBackupNodeModuleFingerprintViewKey reads the parts of a key of the form "backup.<node>.<module>.<fingerprint>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByBackupNodeModuleFingerprintViewKey(key string) (string, string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "backup.") {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = rest[7:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after3
|
||||
v5, after5, found5 := strings.Cut(rest, ".view")
|
||||
if !found5 || v5 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after5
|
||||
if rest != "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
return v1, v3, v5, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByBackupNodeModuleFingerprintViewValue reads one value of the state answers under the form "backup.<node>.<module>.<fingerprint>.view", refusing a field AnswersByBackupNodeModuleFingerprintViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByBackupNodeModuleFingerprintViewValue(raw []byte) (AnswersByBackupNodeModuleFingerprintViewValue, error) {
|
||||
var v AnswersByBackupNodeModuleFingerprintViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByRecordNodeModuleDigestViewKey is the key of one value of the state answers under the form "record.<node>.<module>.<digest>.view".
|
||||
func AnswersByRecordNodeModuleDigestViewKey(node, module, digest string) string {
|
||||
return "record." + node + "." + module + "." + digest + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByRecordNodeModuleDigestViewKey reads the parts of a key of the form "record.<node>.<module>.<digest>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByRecordNodeModuleDigestViewKey(key string) (string, string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "record.") {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = rest[7:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after3
|
||||
v5, after5, found5 := strings.Cut(rest, ".view")
|
||||
if !found5 || v5 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after5
|
||||
if rest != "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
return v1, v3, v5, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByRecordNodeModuleDigestViewValue reads one value of the state answers under the form "record.<node>.<module>.<digest>.view", refusing a field AnswersByRecordNodeModuleDigestViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByRecordNodeModuleDigestViewValue(raw []byte) (AnswersByRecordNodeModuleDigestViewValue, error) {
|
||||
var v AnswersByRecordNodeModuleDigestViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByOutsideNodeModuleFingerprintViewKey is the key of one value of the state answers under the form "outside.<node>.<module>.<fingerprint>.view".
|
||||
func AnswersByOutsideNodeModuleFingerprintViewKey(node, module, fingerprint string) string {
|
||||
return "outside." + node + "." + module + "." + fingerprint + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByOutsideNodeModuleFingerprintViewKey reads the parts of a key of the form "outside.<node>.<module>.<fingerprint>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByOutsideNodeModuleFingerprintViewKey(key string) (string, string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "outside.") {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = rest[8:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after3
|
||||
v5, after5, found5 := strings.Cut(rest, ".view")
|
||||
if !found5 || v5 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after5
|
||||
if rest != "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
return v1, v3, v5, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByOutsideNodeModuleFingerprintViewValue reads one value of the state answers under the form "outside.<node>.<module>.<fingerprint>.view", refusing a field AnswersByOutsideNodeModuleFingerprintViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByOutsideNodeModuleFingerprintViewValue(raw []byte) (AnswersByOutsideNodeModuleFingerprintViewValue, error) {
|
||||
var v AnswersByOutsideNodeModuleFingerprintViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByRevertNodeModuleFingerprintViewKey is the key of one value of the state answers under the form "revert.<node>.<module>.<fingerprint>.view".
|
||||
func AnswersByRevertNodeModuleFingerprintViewKey(node, module, fingerprint string) string {
|
||||
return "revert." + node + "." + module + "." + fingerprint + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByRevertNodeModuleFingerprintViewKey reads the parts of a key of the form "revert.<node>.<module>.<fingerprint>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByRevertNodeModuleFingerprintViewKey(key string) (string, string, string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "revert.") {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = rest[7:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".")
|
||||
if !found1 || v1 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after1
|
||||
v3, after3, found3 := strings.Cut(rest, ".")
|
||||
if !found3 || v3 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after3
|
||||
v5, after5, found5 := strings.Cut(rest, ".view")
|
||||
if !found5 || v5 == "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
rest = after5
|
||||
if rest != "" {
|
||||
return "", "", "", false
|
||||
}
|
||||
return v1, v3, v5, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByRevertNodeModuleFingerprintViewValue reads one value of the state answers under the form "revert.<node>.<module>.<fingerprint>.view", refusing a field AnswersByRevertNodeModuleFingerprintViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByRevertNodeModuleFingerprintViewValue(raw []byte) (AnswersByRevertNodeModuleFingerprintViewValue, error) {
|
||||
var v AnswersByRevertNodeModuleFingerprintViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// AnswersByAssignmentsProposalViewKey is the key of one value of the state answers under the form "assignments.<proposal>.view".
|
||||
func AnswersByAssignmentsProposalViewKey(proposal string) string {
|
||||
return "assignments." + proposal + ".view"
|
||||
}
|
||||
|
||||
// ParseAnswersByAssignmentsProposalViewKey reads the parts of a key of the form "assignments.<proposal>.view", in the order of the form; the last result is false for a key of another form.
|
||||
func ParseAnswersByAssignmentsProposalViewKey(key string) (string, bool) {
|
||||
rest := key
|
||||
if !strings.HasPrefix(rest, "assignments.") {
|
||||
return "", false
|
||||
}
|
||||
rest = rest[12:]
|
||||
v1, after1, found1 := strings.Cut(rest, ".view")
|
||||
if !found1 || v1 == "" {
|
||||
return "", false
|
||||
}
|
||||
rest = after1
|
||||
if rest != "" {
|
||||
return "", false
|
||||
}
|
||||
return v1, true
|
||||
}
|
||||
|
||||
// DecodeAnswersByAssignmentsProposalViewValue reads one value of the state answers under the form "assignments.<proposal>.view", refusing a field AnswersByAssignmentsProposalViewValue does not know and any text after the value.
|
||||
func DecodeAnswersByAssignmentsProposalViewValue(raw []byte) (AnswersByAssignmentsProposalViewValue, error) {
|
||||
var v AnswersByAssignmentsProposalViewValue
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
return v, err
|
||||
}
|
||||
if dec.More() {
|
||||
return v, errors.New("text after the value")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Answer is the status view's answer to an ask.
|
||||
type Answer struct {
|
||||
// the asking it answers
|
||||
Asking string `json:"asking"`
|
||||
// the option the person chose
|
||||
Option string `json:"option"`
|
||||
V int64 `json:"v,omitempty"`
|
||||
// the person's words with it
|
||||
Words string `json:"words,omitempty"`
|
||||
}
|
||||
|
||||
// AnswersByHoldModuleFingerprintViewValue is one value of the state answers under the key hold.<module>.<fingerprint>.view.
|
||||
type AnswersByHoldModuleFingerprintViewValue = Answer
|
||||
|
||||
// AnswersByRestoreNodeModuleFingerprintViewValue is one value of the state answers under the key restore.<node>.<module>.<fingerprint>.view.
|
||||
type AnswersByRestoreNodeModuleFingerprintViewValue = Answer
|
||||
|
||||
// AnswersByBackupNodeModuleFingerprintViewValue is one value of the state answers under the key backup.<node>.<module>.<fingerprint>.view.
|
||||
type AnswersByBackupNodeModuleFingerprintViewValue = Answer
|
||||
|
||||
// AnswersByRecordNodeModuleDigestViewValue is one value of the state answers under the key record.<node>.<module>.<digest>.view.
|
||||
type AnswersByRecordNodeModuleDigestViewValue = Answer
|
||||
|
||||
// AnswersByOutsideNodeModuleFingerprintViewValue is one value of the state answers under the key outside.<node>.<module>.<fingerprint>.view.
|
||||
type AnswersByOutsideNodeModuleFingerprintViewValue = Answer
|
||||
|
||||
// AnswersByRevertNodeModuleFingerprintViewValue is one value of the state answers under the key revert.<node>.<module>.<fingerprint>.view.
|
||||
type AnswersByRevertNodeModuleFingerprintViewValue = Answer
|
||||
|
||||
// AnswersByAssignmentsProposalViewValue is one value of the state answers under the key assignments.<proposal>.view.
|
||||
type AnswersByAssignmentsProposalViewValue = Answer
|
||||
@@ -0,0 +1,52 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
package meshdeliveryview
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestFixtures reads every fixture of seats/mesh-delivery-view/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: "an answer to a hold ask, given in the web view", subject: "", given: "{\"asking\":\"hold.web.0123456789ab.2\",\"option\":\"release\",\"v\":1,\"words\":\"released from the web view\"}", wire: "{\"asking\":\"hold.web.0123456789ab.2\",\"option\":\"release\",\"v\":1,\"words\":\"released from the web view\"}",
|
||||
decode: func(b []byte) (any, error) {
|
||||
var v AnswersByHoldModuleFingerprintViewValue
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshdeliveryview
|
||||
|
||||
go 1.26.0
|
||||
@@ -306,6 +306,26 @@
|
||||
"series": "0.1",
|
||||
"generated-from": "."
|
||||
},
|
||||
{
|
||||
"name": "go-meshdeliveryview",
|
||||
"kind": "package",
|
||||
"language": "go",
|
||||
"paths": [
|
||||
"go/seats/meshdeliveryview"
|
||||
],
|
||||
"series": "0.1",
|
||||
"generated-from": "."
|
||||
},
|
||||
{
|
||||
"name": "ts-meshdeliveryview",
|
||||
"kind": "package",
|
||||
"language": "typescript",
|
||||
"paths": [
|
||||
"ts/seats/meshdeliveryview"
|
||||
],
|
||||
"series": "0.1",
|
||||
"generated-from": "."
|
||||
},
|
||||
{
|
||||
"name": "go-meshwantsclient",
|
||||
"kind": "package",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "an answer to a hold ask, given in the web view",
|
||||
"of": "state:answers/hold.<module>.<fingerprint>.view",
|
||||
"given": {
|
||||
"v": 1,
|
||||
"asking": "hold.web.0123456789ab.2",
|
||||
"option": "release",
|
||||
"words": "released from the web view"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"format": 1,
|
||||
"seat": "mesh-delivery-view",
|
||||
"scope": "mesh",
|
||||
"grain": "whole",
|
||||
"domain": "Delivery",
|
||||
"decision": "novox/hq ADR 0540",
|
||||
"description": "The status view of deliveries (ADR 0540): it serves no verb and says no seat event; its tools and its events delivered, moving, settled and stuck stay its holder's own, and it keeps the person's answers given in the web view.",
|
||||
"states": [
|
||||
{
|
||||
"name": "answers",
|
||||
"template": "state",
|
||||
"view": true,
|
||||
"history": 5,
|
||||
"description": "the person's answer in the web view to an ask of the seat mesh-wants' state asks of a kind that needs no proof of who answered; only the holder writes a key, and only the holder deletes it, once the ask's key has left asks (design 47 G section 717)",
|
||||
"key-forms": [
|
||||
{
|
||||
"key": "hold.<module>.<fingerprint>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under hold.<module>.<fingerprint> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "restore.<node>.<module>.<fingerprint>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under restore.<node>.<module>.<fingerprint> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "backup.<node>.<module>.<fingerprint>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under backup.<node>.<module>.<fingerprint> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "record.<node>.<module>.<digest>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under record.<node>.<module>.<digest> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "outside.<node>.<module>.<fingerprint>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under outside.<node>.<module>.<fingerprint> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "revert.<node>.<module>.<fingerprint>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under revert.<node>.<module>.<fingerprint> (design 47 G A-299)"
|
||||
},
|
||||
{
|
||||
"key": "assignments.<proposal>.view",
|
||||
"value": {
|
||||
"$ref": "#/defs/Answer"
|
||||
},
|
||||
"description": "the status view's answer to the ask of the seat mesh-wants' state asks under assignments.<proposal> (design 47 G A-299)"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"defs": {
|
||||
"Answer": {
|
||||
"type": "object",
|
||||
"description": "the status view's answer to an ask",
|
||||
"properties": {
|
||||
"v": {
|
||||
"type": "integer"
|
||||
},
|
||||
"asking": {
|
||||
"type": "string",
|
||||
"description": "the asking it answers"
|
||||
},
|
||||
"option": {
|
||||
"type": "string",
|
||||
"description": "the option the person chose"
|
||||
},
|
||||
"words": {
|
||||
"type": "string",
|
||||
"description": "the person's words with it"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"asking",
|
||||
"option"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
// The contract of the seat "mesh-delivery-view", defined whole (seats/mesh-delivery-view/seat.json): The status view of deliveries (ADR 0540): it serves no verb and says no seat event; its tools and its events delivered, moving, settled and stuck stay its holder's own, and it keeps the person's answers given in the web view.
|
||||
|
||||
export declare const seat: "mesh-delivery-view";
|
||||
|
||||
export declare const states: {
|
||||
readonly answers: "answers";
|
||||
};
|
||||
|
||||
/** The key of one value of the state answers under the form "hold.<module>.<fingerprint>.view". */
|
||||
export declare function answersByHoldModuleFingerprintViewKey(module: string, fingerprint: string): string;
|
||||
|
||||
/** The parts of a key of the form "hold.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByHoldModuleFingerprintViewKey(_key: string): { module: string; fingerprint: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "restore.<node>.<module>.<fingerprint>.view". */
|
||||
export declare function answersByRestoreNodeModuleFingerprintViewKey(node: string, module: string, fingerprint: string): string;
|
||||
|
||||
/** The parts of a key of the form "restore.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByRestoreNodeModuleFingerprintViewKey(_key: string): { node: string; module: string; fingerprint: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "backup.<node>.<module>.<fingerprint>.view". */
|
||||
export declare function answersByBackupNodeModuleFingerprintViewKey(node: string, module: string, fingerprint: string): string;
|
||||
|
||||
/** The parts of a key of the form "backup.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByBackupNodeModuleFingerprintViewKey(_key: string): { node: string; module: string; fingerprint: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "record.<node>.<module>.<digest>.view". */
|
||||
export declare function answersByRecordNodeModuleDigestViewKey(node: string, module: string, digest: string): string;
|
||||
|
||||
/** The parts of a key of the form "record.<node>.<module>.<digest>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByRecordNodeModuleDigestViewKey(_key: string): { node: string; module: string; digest: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "outside.<node>.<module>.<fingerprint>.view". */
|
||||
export declare function answersByOutsideNodeModuleFingerprintViewKey(node: string, module: string, fingerprint: string): string;
|
||||
|
||||
/** The parts of a key of the form "outside.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByOutsideNodeModuleFingerprintViewKey(_key: string): { node: string; module: string; fingerprint: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "revert.<node>.<module>.<fingerprint>.view". */
|
||||
export declare function answersByRevertNodeModuleFingerprintViewKey(node: string, module: string, fingerprint: string): string;
|
||||
|
||||
/** The parts of a key of the form "revert.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByRevertNodeModuleFingerprintViewKey(_key: string): { node: string; module: string; fingerprint: string } | undefined;
|
||||
|
||||
/** The key of one value of the state answers under the form "assignments.<proposal>.view". */
|
||||
export declare function answersByAssignmentsProposalViewKey(proposal: string): string;
|
||||
|
||||
/** The parts of a key of the form "assignments.<proposal>.view", or undefined for a key of another form. */
|
||||
export declare function parseAnswersByAssignmentsProposalViewKey(_key: string): { proposal: string } | undefined;
|
||||
|
||||
/** the status view's answer to an ask */
|
||||
export interface Answer {
|
||||
/** the asking it answers */
|
||||
"asking": string;
|
||||
/** the option the person chose */
|
||||
"option": string;
|
||||
"v"?: number;
|
||||
/** the person's words with it */
|
||||
"words"?: string;
|
||||
}
|
||||
|
||||
/** is one value of the state answers under the key hold.<module>.<fingerprint>.view. */
|
||||
export type AnswersByHoldModuleFingerprintViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key restore.<node>.<module>.<fingerprint>.view. */
|
||||
export type AnswersByRestoreNodeModuleFingerprintViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key backup.<node>.<module>.<fingerprint>.view. */
|
||||
export type AnswersByBackupNodeModuleFingerprintViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key record.<node>.<module>.<digest>.view. */
|
||||
export type AnswersByRecordNodeModuleDigestViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key outside.<node>.<module>.<fingerprint>.view. */
|
||||
export type AnswersByOutsideNodeModuleFingerprintViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key revert.<node>.<module>.<fingerprint>.view. */
|
||||
export type AnswersByRevertNodeModuleFingerprintViewValue = Answer;
|
||||
|
||||
/** is one value of the state answers under the key assignments.<proposal>.view. */
|
||||
export type AnswersByAssignmentsProposalViewValue = Answer;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
|
||||
|
||||
// The contract of the seat "mesh-delivery-view", defined whole (seats/mesh-delivery-view/seat.json): The status view of deliveries (ADR 0540): it serves no verb and says no seat event; its tools and its events delivered, moving, settled and stuck stay its holder's own, and it keeps the person's answers given in the web view.
|
||||
|
||||
export const seat = "mesh-delivery-view";
|
||||
|
||||
export const states = {
|
||||
answers: "answers",
|
||||
};
|
||||
|
||||
/** The key of one value of the state answers under the form "hold.<module>.<fingerprint>.view". */
|
||||
export function answersByHoldModuleFingerprintViewKey(module, fingerprint) {
|
||||
return "hold." + module + "." + fingerprint + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "hold.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByHoldModuleFingerprintViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("hold.")) return undefined;
|
||||
_rest = _rest.slice(5);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".view");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const fingerprint = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { module, fingerprint };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "restore.<node>.<module>.<fingerprint>.view". */
|
||||
export function answersByRestoreNodeModuleFingerprintViewKey(node, module, fingerprint) {
|
||||
return "restore." + node + "." + module + "." + fingerprint + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "restore.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByRestoreNodeModuleFingerprintViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("restore.")) return undefined;
|
||||
_rest = _rest.slice(8);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const node = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 1);
|
||||
const _at5 = _rest.indexOf(".view");
|
||||
if (_at5 <= 0) return undefined;
|
||||
const fingerprint = _rest.slice(0, _at5);
|
||||
_rest = _rest.slice(_at5 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { node, module, fingerprint };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "backup.<node>.<module>.<fingerprint>.view". */
|
||||
export function answersByBackupNodeModuleFingerprintViewKey(node, module, fingerprint) {
|
||||
return "backup." + node + "." + module + "." + fingerprint + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "backup.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByBackupNodeModuleFingerprintViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("backup.")) return undefined;
|
||||
_rest = _rest.slice(7);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const node = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 1);
|
||||
const _at5 = _rest.indexOf(".view");
|
||||
if (_at5 <= 0) return undefined;
|
||||
const fingerprint = _rest.slice(0, _at5);
|
||||
_rest = _rest.slice(_at5 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { node, module, fingerprint };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "record.<node>.<module>.<digest>.view". */
|
||||
export function answersByRecordNodeModuleDigestViewKey(node, module, digest) {
|
||||
return "record." + node + "." + module + "." + digest + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "record.<node>.<module>.<digest>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByRecordNodeModuleDigestViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("record.")) return undefined;
|
||||
_rest = _rest.slice(7);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const node = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 1);
|
||||
const _at5 = _rest.indexOf(".view");
|
||||
if (_at5 <= 0) return undefined;
|
||||
const digest = _rest.slice(0, _at5);
|
||||
_rest = _rest.slice(_at5 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { node, module, digest };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "outside.<node>.<module>.<fingerprint>.view". */
|
||||
export function answersByOutsideNodeModuleFingerprintViewKey(node, module, fingerprint) {
|
||||
return "outside." + node + "." + module + "." + fingerprint + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "outside.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByOutsideNodeModuleFingerprintViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("outside.")) return undefined;
|
||||
_rest = _rest.slice(8);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const node = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 1);
|
||||
const _at5 = _rest.indexOf(".view");
|
||||
if (_at5 <= 0) return undefined;
|
||||
const fingerprint = _rest.slice(0, _at5);
|
||||
_rest = _rest.slice(_at5 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { node, module, fingerprint };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "revert.<node>.<module>.<fingerprint>.view". */
|
||||
export function answersByRevertNodeModuleFingerprintViewKey(node, module, fingerprint) {
|
||||
return "revert." + node + "." + module + "." + fingerprint + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "revert.<node>.<module>.<fingerprint>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByRevertNodeModuleFingerprintViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("revert.")) return undefined;
|
||||
_rest = _rest.slice(7);
|
||||
const _at1 = _rest.indexOf(".");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const node = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 1);
|
||||
const _at3 = _rest.indexOf(".");
|
||||
if (_at3 <= 0) return undefined;
|
||||
const module = _rest.slice(0, _at3);
|
||||
_rest = _rest.slice(_at3 + 1);
|
||||
const _at5 = _rest.indexOf(".view");
|
||||
if (_at5 <= 0) return undefined;
|
||||
const fingerprint = _rest.slice(0, _at5);
|
||||
_rest = _rest.slice(_at5 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { node, module, fingerprint };
|
||||
}
|
||||
|
||||
/** The key of one value of the state answers under the form "assignments.<proposal>.view". */
|
||||
export function answersByAssignmentsProposalViewKey(proposal) {
|
||||
return "assignments." + proposal + ".view";
|
||||
}
|
||||
|
||||
/** The parts of a key of the form "assignments.<proposal>.view", or undefined for a key of another form. */
|
||||
export function parseAnswersByAssignmentsProposalViewKey(_key) {
|
||||
let _rest = _key;
|
||||
if (!_rest.startsWith("assignments.")) return undefined;
|
||||
_rest = _rest.slice(12);
|
||||
const _at1 = _rest.indexOf(".view");
|
||||
if (_at1 <= 0) return undefined;
|
||||
const proposal = _rest.slice(0, _at1);
|
||||
_rest = _rest.slice(_at1 + 5);
|
||||
if (_rest !== "") return undefined;
|
||||
return { proposal };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"lockfileVersion": 3,
|
||||
"name": "@novox/mesh-delivery-contracts-mesh-delivery-view",
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@novox/mesh-delivery-contracts-mesh-delivery-view",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
},
|
||||
"requires": true,
|
||||
"version": "0.1.0"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"description": "The contract of the seat mesh-delivery-view, generated from its definition.",
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./index.js",
|
||||
"types": "./index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"parts"
|
||||
],
|
||||
"name": "@novox/mesh-delivery-contracts-mesh-delivery-view",
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func fullConf(dir string) string {
|
||||
teller = append(teller, keepsOf(bucketsOf(tellerModule).marks)...)
|
||||
// The assigner's asks and the view's answers, each by its read tool and its views family (ADR 0615, DLV-M3; A-175), and the
|
||||
// teller's own first-views and findings; the buckets themselves are no longer the teller's to read.
|
||||
teller = append(append(append(teller, viewstest.Grants(assignerModule, assignerModule+"."+assignerAsksState, tellerConsumer)...), viewstest.Grants(viewModule, viewModule+"."+viewstate.ViewAnswersReadTool, tellerConsumer)...), keepsOf(bucketsOf(tellerModule).firstViews)...)
|
||||
teller = append(append(append(teller, viewstest.Grants(assignerModule, assignerModule+"."+assignerAsksState, tellerConsumer)...), viewstest.Grants(viewModule, viewModule+"."+viewstate.ViewAnswersTool, tellerConsumer)...), keepsOf(bucketsOf(tellerModule).firstViews)...)
|
||||
teller = append(teller, keepsOf(bucketsOf(tellerModule).findings)...)
|
||||
view := append(append(readOf(tellerAnswers), readOf(assignerAsks)...), keepsOf(viewAnswers)...)
|
||||
assigner := keepsOf(assignerAsks)
|
||||
@@ -194,7 +194,7 @@ func startFull(t *testing.T) *fullBed {
|
||||
// The assigner as the owner of its asks: its read tool and its views family (ADR 0615).
|
||||
viewstest.Serve(t, ctx, js, ctl, assignerModule, "asks", assignerModule+"."+assignerAsksState, tellerConsumer)
|
||||
// The view as the owner of its answers, as the teller follows them (A-175, A-178).
|
||||
viewstest.Serve(t, ctx, js, ctl, viewModule, viewstate.ViewAnswersState, viewModule+"."+viewstate.ViewAnswersReadTool, tellerConsumer)
|
||||
viewstest.Serve(t, ctx, js, ctl, viewModule, viewstate.ViewAnswersState, viewModule+"."+viewstate.ViewAnswersTool, tellerConsumer)
|
||||
return &fullBed{srv: srv, ctl: ctl, js: js, ctx: ctx}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
}
|
||||
assignerKV := jetstream.KeyValue(asks)
|
||||
// The view's answers to the assigner's asks (issue 1297 B10, A-175): followed as the assigner's asks are, never its bucket.
|
||||
answered, err := reader.Follow(viewModule, viewstate.ViewAnswersState, viewModule+"."+viewstate.ViewAnswersReadTool)
|
||||
answered, err := reader.Follow(viewModule, viewstate.ViewAnswersState, viewModule+"."+viewstate.ViewAnswersTool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -41,11 +41,9 @@ func TestTheNamesAreTheManifests(t *testing.T) {
|
||||
if want := "seat:mesh-wants.views." + assignerAsksState; !slices.Contains(m.Consumes, want) || slices.ContainsFunc(m.Invokes, func(e string) bool { return strings.HasPrefix(e, assignerModule+".") }) {
|
||||
t.Errorf("the teller follows %s and invokes nothing of the assigner's, its manifest's consumes are %v and invokes %v", want, m.Consumes, m.Invokes)
|
||||
}
|
||||
if want := viewModule + "." + viewstate.ViewAnswersReadTool; !slices.Contains(m.Invokes, want) {
|
||||
t.Errorf("the teller follows the view's answers by %s, its manifest's invokes are %v", want, m.Invokes)
|
||||
}
|
||||
if want := viewModule + ".views." + viewstate.ViewAnswersState; !slices.Contains(m.Consumes, want) {
|
||||
t.Errorf("the teller follows %s, its manifest's consumes are %v", want, m.Consumes)
|
||||
// Design 47 G §717: the view's answers are the seat mesh-delivery-view's view, followed in seat form; no invoke names its tool.
|
||||
if want := "seat:mesh-delivery-view.views." + viewstate.ViewAnswersState; !slices.Contains(m.Consumes, want) || slices.ContainsFunc(m.Invokes, func(e string) bool { return strings.HasPrefix(e, viewModule+".") }) {
|
||||
t.Errorf("the teller follows %s and invokes nothing of the view's, its manifest's consumes are %v and invokes %v", want, m.Consumes, m.Invokes)
|
||||
}
|
||||
if want := "views." + answersState; !slices.Contains(m.Emits, want) {
|
||||
t.Errorf("the teller says %s, its manifest's emits are %v", want, m.Emits)
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
// asks of the assigner that need no proof of who answered (the hold of a fingerprint and the restore of a data module set back,
|
||||
// mesh-sdk go/delivery AskNeedsProof); the view writes its answer under `<ask key>.view` in its state answers, and the teller,
|
||||
// which alone fills an ask's answer, takes it from the picture it follows of that state (the view's views family, first view
|
||||
// by view_read_answers; design 47 G A-175) as it takes a warrant from the phone: under the ask's own key, once, by
|
||||
// by its first-view tool answers; design 47 G A-175, §717) as it takes a warrant from the phone: under the ask's own key, once, by
|
||||
// compare-and-set.
|
||||
|
||||
// OnViewAnswer handles a key put in the followed picture of the view's answers. A key that is no view answer key, or is the answer to an ask that
|
||||
|
||||
@@ -104,14 +104,14 @@ func TestManifestDeclarations(t *testing.T) { // 1240/AC1
|
||||
}
|
||||
// Its own states answers and teller-marks are said as its views family views.answers, read by teller_read_answers (A-175, A-178).
|
||||
// The join: its first view asked again by hand is a hand act, recorded through the seat (views.StatusTools).
|
||||
if want := []string{"mesh-delivery-view.view_read_answers", "seat:mesh-hand-acts.hand-act", "seat:mesh-catalog.registrations", "seat:mesh-broker.show", "seat:operator-channel.notify",
|
||||
if want := []string{ "seat:mesh-hand-acts.hand-act", "seat:mesh-catalog.registrations", "seat:mesh-broker.show", "seat:operator-channel.notify",
|
||||
// A-126: who holds the seat operator-channel, whose state asks holds the router's record of its asks (operatorask.Bucket).
|
||||
"seat:mesh-module-assigner.assignments"}; !reflect.DeepEqual(m.Invokes, want) {
|
||||
t.Errorf("invokes = %v, want %v", m.Invokes, want)
|
||||
}
|
||||
// design 47 G §335 (TL1): the widening of a pipeline end is told through the seat operator-channel and kept in widens-said.
|
||||
// design 47 G §387: the keeper's ask for the findings is heard, and the finding stream is declared (§383).
|
||||
if want := []string{"mesh-conditions.findings-asked", "seat:mesh-wants.views.asks", "mesh-delivery-view.views.answers", "mesh-catalog.registration-changed", "mesh-pipeline-runner.pipeline-ended", "mesh-delivery.recovery-merged", "mesh-delivery.record-opened", "mesh-broker.recreated", "mesh-broker.dropped"}; !reflect.DeepEqual(m.Consumes, want) {
|
||||
if want := []string{"mesh-conditions.findings-asked", "seat:mesh-wants.views.asks", "seat:mesh-delivery-view.views.answers", "mesh-catalog.registration-changed", "mesh-pipeline-runner.pipeline-ended", "mesh-delivery.recovery-merged", "mesh-delivery.record-opened", "mesh-broker.recreated", "mesh-broker.dropped"}; !reflect.DeepEqual(m.Consumes, want) {
|
||||
t.Errorf("consumes = %v, want %v", m.Consumes, want)
|
||||
}
|
||||
if want := []string{"operator-channel"}; !reflect.DeepEqual(sorted(m.Uses), want) {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"teller_widens_said"
|
||||
],
|
||||
"invokes": [
|
||||
"mesh-delivery-view.view_read_answers",
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"seat:mesh-catalog.registrations",
|
||||
"seat:mesh-broker.show",
|
||||
@@ -21,7 +20,7 @@
|
||||
"consumes": [
|
||||
"mesh-conditions.findings-asked",
|
||||
"seat:mesh-wants.views.asks",
|
||||
"mesh-delivery-view.views.answers",
|
||||
"seat:mesh-delivery-view.views.answers",
|
||||
"mesh-catalog.registration-changed",
|
||||
"mesh-pipeline-runner.pipeline-ended",
|
||||
"mesh-delivery.recovery-merged",
|
||||
|
||||
@@ -186,6 +186,8 @@ type putter struct{ puts map[string][]byte }
|
||||
|
||||
func (p *putter) Put(key string, value []byte) error { p.puts[key] = value; return nil }
|
||||
|
||||
func (p *putter) Delete(key string) error { delete(p.puts, key); return nil }
|
||||
|
||||
func serveWith(t *testing.T, m *view.Model) string {
|
||||
t.Helper()
|
||||
dir, err := os.MkdirTemp(os.Getenv("TMPDIR"), "c")
|
||||
|
||||
@@ -466,7 +466,7 @@ func main() {
|
||||
// view_first_views and view_first_view_again: where the view's process stands with its first views of the indexer's and
|
||||
// the assigner's states (ADR 0615 §6), and a re-read by hand.
|
||||
tools := append(Tools(r, u), gate.Tools()...)
|
||||
tools = append(tools, AnswersReadTool(func(name string) views.Source { return views.KeptSource{State: stdio.State(name)} }, time.Now))
|
||||
tools = append(tools, AnswersTool(views.ParseCallers(os.Getenv(views.CallersEnv(viewstate.ViewAnswersTool))), func(name string) views.Source { return views.KeptSource{State: stdio.State(name)} }, time.Now))
|
||||
tools = append(tools, views.StatusTools(viewstate.ViewModule, "view_first_views", "view_first_view_again", stdio.State(views.StatusState), meshhandactsclient.Recorder{Ask: stdio.Ask}, time.Now)...)
|
||||
if err := stdio.Serve("", tools); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[mesh-delivery-view-tools] %v\n", err)
|
||||
@@ -474,12 +474,13 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// AnswersReadTool is view_read_answers, the view's ordinary read tool of its own state answers (mesh-sdk views.ReadTool): the
|
||||
// teller's first view of the answers the view says on views.answers (design 47 G A-175, A-178).
|
||||
func AnswersReadTool(state func(string) views.Source, now func() time.Time) stdio.Tool {
|
||||
return views.ReadTool(viewstate.ViewModule, viewstate.ViewAnswersReadTool, viewstate.ViewAnswersState,
|
||||
"the operator's answers given in the view to the assigner's asks, one key <ask key>.view each, which the teller fills the ask from.",
|
||||
state(viewstate.ViewAnswersState), state(views.MarksState), now)
|
||||
// AnswersTool is answers, the first-view tool of the seat mesh-delivery-view's state answers (mesh-sdk views.FirstViewTool),
|
||||
// answered to the callers its list names (the teller): its first view of the answers the view says on views.answers
|
||||
// (design 47 G A-175, A-178, §717, A-301).
|
||||
func AnswersTool(callers stdio.Callers, state func(string) views.Source, now func() time.Time) stdio.Tool {
|
||||
return views.FirstViewTool(viewstate.ViewModule, viewstate.ViewAnswersTool, viewstate.ViewAnswersState,
|
||||
"the operator's answers given in the view to the asks of the seat mesh-wants, one key <ask key>.view each, which the teller fills the ask from.",
|
||||
callers, state(viewstate.ViewAnswersState), state(views.MarksState), now)
|
||||
}
|
||||
|
||||
// pendingOf asks the indexer's tool indexer_pending (declared in invokes): what it holds back and why (ADR 0633 §5).
|
||||
|
||||
@@ -256,24 +256,24 @@ var catalogAnswer = meshcatalog.RevisionAnswer{
|
||||
// §506, §578), never one computed again from the manifest whole.
|
||||
const manifestDigestA = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
// view_read_answers answers the view's own answers as every owner's read tool answers its state (design 47 G A-178): one
|
||||
// key's value, and every key when none is named.
|
||||
// answers is the first-view tool of the seat mesh-delivery-view's state answers (design 47 G A-178, §717, A-301): a page of every
|
||||
// key, answered to the teller its callers list names and refused to any other caller.
|
||||
func TestTheViewReadsItsAnswersAsAnOwner(t *testing.T) {
|
||||
answers := source{"hold.plex.ab.view": `{"asking":"a1","option":"release"}`}
|
||||
tool := AnswersReadTool(func(name string) views.Source {
|
||||
tool := AnswersTool(views.ParseCallers("mesh-delivery-teller"), func(name string) views.Source {
|
||||
if name == viewstate.ViewAnswersState {
|
||||
return answers
|
||||
}
|
||||
return source{}
|
||||
}, time.Now)
|
||||
if tool.Name != "view_read_answers" {
|
||||
if tool.Name != "answers" {
|
||||
t.Fatalf("the tool is %s", tool.Name)
|
||||
}
|
||||
for args, want := range map[string]map[string]any{"release": {"key": "hold.plex.ab.view"}, "hold.plex.ab.view": {}} {
|
||||
out, err := tool.Run(want)
|
||||
raw, _ := json.Marshal(out)
|
||||
if err != nil || !strings.Contains(string(raw), args) {
|
||||
t.Errorf("%v: %s, %v", args, raw, err)
|
||||
}
|
||||
// Answered only to the callers its list names: the teller, never a call no runtime proved.
|
||||
if !strings.Contains(tool.Description, "mesh-delivery-teller") {
|
||||
t.Errorf("the tool's callers are not the teller: %s", tool.Description)
|
||||
}
|
||||
if out, err := tool.Run(map[string]any{}); err == nil {
|
||||
t.Errorf("an unproven caller is answered: %v", out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
|
||||
// sayAnswers says each change of the view's own state answers on its views family (`views.answers`), from the revision its
|
||||
// marks state view-marks says it said up to, as every owner says its states (design 47 G A-175, A-178): the teller follows it
|
||||
// by view_read_answers and that family, never by reading the state. A watch that ends is sent on errs, and the program ends
|
||||
// by its first-view tool answers and that family, never by reading the state. A watch that ends is sent on errs, and the program ends
|
||||
// with it, loudly.
|
||||
func sayAnswers(ctx context.Context, js jetstream.JetStream, nc process.Subscriber, cred process.Account, writer views.WireWriter, errs chan<- error, logf func(string, ...any)) {
|
||||
marks := cred.Module + "_" + views.MarksState
|
||||
@@ -213,7 +213,7 @@ func sayAnswers(ctx context.Context, js jetstream.JetStream, nc process.Subscrib
|
||||
em := views.Emitter{Owner: viewstate.ViewModule, Subject: cred.EventSubject, Publish: views.JetStreamPublish(js), Marks: mk, Findings: writer, Logf: logf}
|
||||
process.AwaitBucket(ctx, js, nc, viewstate.BucketsOf(cred.Module).Answers, "the view's answers are not said on its views family", logf).Ready(func(kv jetstream.KeyValue) {
|
||||
if err := em.Start(ctx, viewstate.ViewAnswersState, kv, errs); err != nil {
|
||||
logf("%v: the teller asks view_read_answers at each change until the view starts again", err)
|
||||
logf("%v: the teller asks the first-view tool answers at each change until the view starts again", err)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -236,6 +236,16 @@ func (w kvWriter) Put(key string, value []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete removes a key of the view's own answers: the answer to an ask that left asks, which only the view deletes (design 47 G
|
||||
// §717).
|
||||
func (w kvWriter) Delete(key string) error {
|
||||
kv, err := w.js.KeyValue(w.ctx, w.bucket)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the bucket %s: %w", w.bucket, err)
|
||||
}
|
||||
return kv.Delete(w.ctx, key)
|
||||
}
|
||||
|
||||
// putReach writes a reach value under its key in the view's own state reach (ADR 0556 clause 2), its only writer.
|
||||
func putReach(ctx context.Context, js jetstream.JetStream, bucket string, w view.ReachWrite) (uint64, error) {
|
||||
kv, err := js.KeyValue(ctx, bucket)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -19,8 +20,9 @@ import (
|
||||
|
||||
// memWriter is the view's bucket answers in memory.
|
||||
type memWriter struct {
|
||||
puts map[string][]byte
|
||||
fail error
|
||||
puts map[string][]byte
|
||||
deleted []string
|
||||
fail error
|
||||
}
|
||||
|
||||
func (w *memWriter) Put(key string, value []byte) error {
|
||||
@@ -34,6 +36,15 @@ func (w *memWriter) Put(key string, value []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *memWriter) Delete(key string) error {
|
||||
if w.fail != nil {
|
||||
return w.fail
|
||||
}
|
||||
w.deleted = append(w.deleted, key)
|
||||
delete(w.puts, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// holdAsk is a key of the assigner's asks: the ask about a held fingerprint, as a fixture (in release 5 the assigner writes
|
||||
// none yet; the value is `{"v":1,"ask":<the router's ask>}`, as the gate's minus group and heads).
|
||||
func holdAsk(t *testing.T) (Entry, oc.Ask) {
|
||||
@@ -93,6 +104,14 @@ func TestTheViewWritesItsAnswerUnderTheAsksViewKey(t *testing.T) { // 1297/B9a A
|
||||
if len(got) != 1 || got[0].Chosen != "release" {
|
||||
t.Errorf("asks = %+v, want the ask with chosen release", got)
|
||||
}
|
||||
// Design 47 G §717: only the holder deletes its answer, once the ask's key has left asks, so no answer outlives its ask.
|
||||
if len(w.deleted) != 0 {
|
||||
t.Fatalf("deleted %v while the ask stands", w.deleted)
|
||||
}
|
||||
fill(m, Entry{Bucket: AssignerAsksBucket, Key: e.Key, Deleted: true, At: t0})
|
||||
if !slices.Equal(w.deleted, []string{e.Key + ".view"}) {
|
||||
t.Errorf("deleted %v once the ask left asks, want %s.view", w.deleted, e.Key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheViewRefusesWhatItMayNotAnswer(t *testing.T) { // 1297/B9a AC
|
||||
|
||||
@@ -237,6 +237,7 @@ type UnreadableRow struct {
|
||||
type Model struct {
|
||||
mu sync.Mutex
|
||||
own viewstate.Buckets // its own buckets, named from its credential's module (A-296)
|
||||
left []string // the asks heard leaving asks whose answer the view still keeps (§717)
|
||||
placed *meshmoduleassignerclient.Placed // the seat's assignments (the assigner's state, ADR 0567, ADR 0549 §3)
|
||||
builds map[string]buildEntry // by <module>.build.<id>
|
||||
groups map[string]groupEntry // the indexer's candidates, by group
|
||||
@@ -391,7 +392,10 @@ func (m *Model) Apply(e Entry) {
|
||||
writes, reached := m.reachNow()
|
||||
say, put := m.deliveredEvent, m.reachPut
|
||||
sayMotion := m.motionEvent
|
||||
left, w := m.left, m.writer
|
||||
m.left = nil
|
||||
m.mu.Unlock()
|
||||
m.deleteAnswers(w, left)
|
||||
for _, event := range events {
|
||||
if say != nil && say(event) != nil {
|
||||
m.unsay(event)
|
||||
@@ -401,6 +405,22 @@ func (m *Model) Apply(e Entry) {
|
||||
m.sayMotion(sayMotion, motion)
|
||||
}
|
||||
|
||||
// deleteAnswers deletes the view's answers to the asks that left asks, after the model's lock is released; one not deleted is
|
||||
// tried again at the next change the view hears.
|
||||
func (m *Model) deleteAnswers(w Writer, left []string) {
|
||||
for _, askKey := range left {
|
||||
key, err := viewstate.ViewAnswerKey(askKey)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if w == nil || w.Delete(key) != nil {
|
||||
m.mu.Lock()
|
||||
m.left = append(m.left, askKey)
|
||||
m.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sayMotion says the motion events after the model's lock is released; one not said is forgotten as told, so the next change of
|
||||
// its want, have or stuck key says it again.
|
||||
func (m *Model) sayMotion(say func(MotionEvent) error, events []MotionEvent) {
|
||||
@@ -579,6 +599,10 @@ func (m *Model) apply(e Entry) {
|
||||
case AssignerAsksBucket:
|
||||
if e.Deleted {
|
||||
delete(m.aasks, e.Key)
|
||||
// The view's answer outlives no ask: once the ask has left asks, the view deletes its answer (design 47 G §717).
|
||||
if _, ok := m.chosen[e.Key]; ok {
|
||||
m.left = append(m.left, e.Key)
|
||||
}
|
||||
return
|
||||
}
|
||||
a, err := decodeAssignerAsk(e.Key, e.Value)
|
||||
@@ -989,6 +1013,8 @@ func (m *Model) chosenOf(key string, ask oc.Ask) string {
|
||||
// Writer puts a key of the view's bucket answers, the only state the view writes.
|
||||
type Writer interface {
|
||||
Put(key string, value []byte) error
|
||||
// Delete removes a key of the view's answers: the answer to an ask that left asks (design 47 G §717).
|
||||
Delete(key string) error
|
||||
}
|
||||
|
||||
// SetWriter gives the model the bucket its answers are written to.
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
)
|
||||
|
||||
// The controller's manifest reader is mesh-controller internal/catalogue (ParseManifest), an internal package of another
|
||||
@@ -36,9 +37,11 @@ type artifact struct {
|
||||
From string `json:"from"`
|
||||
Binary string `json:"binary"`
|
||||
Loads []string `json:"loads"`
|
||||
Paths []string `json:"paths"`
|
||||
Series string `json:"series"`
|
||||
Context *struct {
|
||||
// Env is the bundle's environment: the tools program's callers list of its first-view tool answers (A-301).
|
||||
Env map[string]string `json:"env"`
|
||||
Paths []string `json:"paths"`
|
||||
Series string `json:"series"`
|
||||
Context *struct {
|
||||
Repository string `json:"repository"`
|
||||
} `json:"context"`
|
||||
}
|
||||
@@ -60,7 +63,15 @@ type stream struct {
|
||||
MaxMiB int `json:"max-mib"`
|
||||
}
|
||||
|
||||
// claim is a seat the manifest claims (design 47 G §717: the status view claims mesh-delivery-view and serves none of its own).
|
||||
type claim struct {
|
||||
Name string `json:"name"`
|
||||
Scope string `json:"scope"`
|
||||
Serves []string `json:"serves"`
|
||||
}
|
||||
|
||||
type manifest struct {
|
||||
Claims []claim `json:"claims"`
|
||||
State []state `json:"state"`
|
||||
Module string `json:"module"`
|
||||
Moved bool `json:"moved"`
|
||||
@@ -130,6 +141,15 @@ func load(t *testing.T) (manifest, map[string]json.RawMessage) {
|
||||
|
||||
func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
|
||||
m, top := load(t)
|
||||
for _, a := range m.Build.Artifacts {
|
||||
if a.Name == "tools" && a.Env[views.CallersEnv("answers")] != "mesh-delivery-teller" {
|
||||
t.Errorf("the tools' env = %v, want the callers of answers mesh-delivery-teller", a.Env)
|
||||
}
|
||||
}
|
||||
// Design 47 G §717: it claims the seat mesh-delivery-view, scope mesh, serving no verb, and its first-view tool answers.
|
||||
if want := []claim{{Name: "mesh-delivery-view", Scope: "mesh", Serves: []string{}}}; !reflect.DeepEqual(m.Claims, want) {
|
||||
t.Errorf("claims = %+v, want %+v", m.Claims, want)
|
||||
}
|
||||
if m.Module != "mesh-delivery-view" {
|
||||
t.Errorf("module = %q", m.Module)
|
||||
}
|
||||
@@ -139,7 +159,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("reads = %v, want exactly %v", got, want)
|
||||
}
|
||||
for _, k := range []string{"provides", "claims"} {
|
||||
for _, k := range []string{"provides"} { // its one claim, a seat serving no verb, is checked above (§717)
|
||||
if _, ok := top[k]; ok {
|
||||
t.Errorf("the manifest declares %q: the view writes only its answers", k)
|
||||
}
|
||||
@@ -203,7 +223,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
|
||||
}
|
||||
// The two read tools of the indexer's modules (issue 1562), carried by a bundle the runtime launches; the indexer
|
||||
// itself serves no tool (ADR 0437 §4). Carrying them gives the tool runner read access to every bucket the view reads.
|
||||
if want := []string{"view_status", "indexer_module", "indexer_modules", "indexer_candidate", "indexer_candidates", "indexer_predefined", "indexer_config_candidates", "indexer_packages", "builder_build", "builder_builds", "builder_history", "assigner_wants", "assigner_want", "assigner_differences", "node_haves", "node_trusts", "build_usage", "view_reach", "indexer_module_history", "indexer_heard", "view_tiers", "view_first_views", "view_first_view_again", "node_manifest_reads", "view_seat_list", "view_seat_list_again", "view_read_answers"}; !reflect.DeepEqual(m.Tools, want) {
|
||||
if want := []string{"view_status", "indexer_module", "indexer_modules", "indexer_candidate", "indexer_candidates", "indexer_predefined", "indexer_config_candidates", "indexer_packages", "builder_build", "builder_builds", "builder_history", "assigner_wants", "assigner_want", "assigner_differences", "node_haves", "node_trusts", "build_usage", "view_reach", "indexer_module_history", "indexer_heard", "view_tiers", "view_first_views", "view_first_view_again", "node_manifest_reads", "view_seat_list", "view_seat_list_again", "answers"}; !reflect.DeepEqual(m.Tools, want) {
|
||||
t.Errorf("tools = %v, want %v", m.Tools, want)
|
||||
}
|
||||
// D-11: the holders and buckets the view names are its manifest's (no contract names a holder, novox/hq ADR 0634 §1): a
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"node_manifest_reads",
|
||||
"view_seat_list",
|
||||
"view_seat_list_again",
|
||||
"view_read_answers"
|
||||
"answers"
|
||||
],
|
||||
"emits": [
|
||||
"delivered",
|
||||
@@ -40,6 +40,13 @@
|
||||
"stuck",
|
||||
"views.answers"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-delivery-view",
|
||||
"scope": "mesh",
|
||||
"serves": []
|
||||
}
|
||||
],
|
||||
"state": [
|
||||
{
|
||||
"name": "answers",
|
||||
@@ -226,7 +233,10 @@
|
||||
"binary": "mesh-delivery-view-tools",
|
||||
"loads": [
|
||||
"mesh-delivery-view-tools"
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"MESH_VIEW_CALLERS_ANSWERS": "mesh-delivery-teller"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "files",
|
||||
|
||||
@@ -146,9 +146,10 @@ func SameReach(a, b Reach) bool {
|
||||
const (
|
||||
ViewAnswersState = "answers"
|
||||
ViewAnswersHistory = 5
|
||||
// ViewAnswersReadTool is the view's read tool of its state answers (mesh-sdk views.ReadTool), whose changes it says on its
|
||||
// views family as views.answers; its marks are its state view-marks (views.MarksState) (design 47 G A-178).
|
||||
ViewAnswersReadTool = "view_read_answers"
|
||||
// ViewAnswersTool is the first-view tool of the seat mesh-delivery-view's state answers (mesh-sdk views.FirstViewTool), named
|
||||
// for the state, whose changes the view says on its views family as views.answers; its marks are its state view-marks
|
||||
// (views.MarksState) (design 47 G A-178, §717, A-301).
|
||||
ViewAnswersTool = ViewAnswersState
|
||||
)
|
||||
|
||||
// ViewAnswer is the value of the view's answer to an ask of the assigner: the asking it answers, the option chosen and the words
|
||||
|
||||
Reference in New Issue
Block a user