The manifest validator reads kept state in both forms; per-machine in requires is refused
A process's bus.state, a seat contribution and a seat's records naming a key-value entry asked in requires were refused, where the old state section is accepted (issue 1966, ADR 0595 §11). They now read catalogue.KeptStates. A per-machine key-value entry in requires is refused with its reason: its binding names no machine's key, so no machine could be held to its own. Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -166,6 +166,15 @@ func BusStateProblems(m catalogue.Manifest) []string {
|
||||
"%s: the name is also kept in the old section %s; one local name is one form, so a module that moves an "+
|
||||
"entry removes it from the old section (novox/hq ADR 0595 §11)", at, section))
|
||||
}
|
||||
// A key-value entry kept one bucket key per machine is not issued in the new form yet (issue 1966, the lead's
|
||||
// ruling): its binding names no per-machine key, so neither the grants part nor the tool runner could hold each
|
||||
// machine to its own key (ADR 0260). Refused with the way that holds, never issued as a whole bucket.
|
||||
if e.Storage == catalogue.StorageKeyValue && string(e.Options[catalogue.OptionPerMachine]) == "true" {
|
||||
problems = append(problems, fmt.Sprintf(
|
||||
"%s: per-machine is not issued in `requires` yet, since its binding names no machine's key and each "+
|
||||
"machine would reach every key; keep it in the old section state with per-machine until the binding "+
|
||||
"carries it (novox/hq ADR 0260, ADR 0595 §1)", at))
|
||||
}
|
||||
problems = append(problems, busEntryProblems(at, e, terminal)...)
|
||||
}
|
||||
return problems
|
||||
|
||||
@@ -28,6 +28,14 @@ func TestBusStateIsJudgedOnce(t *testing.T) {
|
||||
{"within bounds", manifest(`{"name":"cache","storage":"key-value","template":"state","options":{"history":8,"key-ttl":true}},` +
|
||||
`{"name":"audit","storage":"stream","template":"log","options":{"max-mib":64,"max-age-days":365}},` +
|
||||
`{"name":"files","storage":"object-store","template":"objects","options":{"max-mib":2048}},` + ledger), nil},
|
||||
// Issue 1966: a process's bus state names a key-value entry of `requires` by its local name, as an old state's
|
||||
// (ADR 0595 §11); one per machine is refused with the way that holds, its binding naming no machine's key (Q3).
|
||||
{"a process naming a requires key-value entry", `{"module":"a","version":"1","requires":[{"name":"cache","storage":"key-value","template":"state"}],` +
|
||||
`"resources":[{"id":"u","type":"user","name":"a"},{"id":"p","type":"process","user":"a","run":["./a"],"bus":{"state":["cache"]}}]}`, nil},
|
||||
{"a process naming a state it keeps in neither form", `{"module":"a","version":"1","requires":[{"name":"cache","storage":"key-value","template":"state"}],` +
|
||||
`"resources":[{"id":"u","type":"user","name":"a"},{"id":"p","type":"process","user":"a","run":["./a"],"bus":{"state":["other"]}}]}`, []string{"bus reads and writes state \"other\""}},
|
||||
{"per-machine in requires", manifest(`{"name":"x","storage":"key-value","template":"state","options":{"per-machine":true}}`),
|
||||
[]string{"\"x\"", "per-machine is not issued in `requires` yet", "old section state"}},
|
||||
// 1966/AC7: each refused case, naming the module, the entry and the field
|
||||
{"unknown storage type", manifest(`{"name":"x","storage":"tape"}`), []string{"a's bus state \"x\"", "storage type \"tape\""}},
|
||||
{"unknown template", manifest(`{"name":"x","storage":"stream","template":"pile"}`), []string{"\"x\"", "template \"pile\""}},
|
||||
|
||||
@@ -3913,9 +3913,11 @@ func ProcessBusProblems(m catalogue.Manifest) []string {
|
||||
for _, s := range m.Streams {
|
||||
streams[s.Name] = true
|
||||
}
|
||||
// What the module keeps, in either form (catalogue.KeptStates, issue 1966): a process names a key-value entry of
|
||||
// `requires` by its local name as it names an old state (ADR 0595 §11).
|
||||
state := map[string]bool{}
|
||||
for _, s := range m.State {
|
||||
state[s.Name] = true
|
||||
for _, s := range catalogue.KeptStates(m) {
|
||||
state[s] = true
|
||||
}
|
||||
emits := map[string]bool{}
|
||||
for _, e := range m.EmitsAll() {
|
||||
@@ -4306,8 +4308,8 @@ func ownStateProblems(m catalogue.Manifest, i int, r catalogue.Receivable, c cat
|
||||
return nil
|
||||
}
|
||||
keeps := map[string]bool{}
|
||||
for _, s := range m.State {
|
||||
keeps[s.Name] = true
|
||||
for _, s := range catalogue.KeptStates(m) { // either form (issue 1966)
|
||||
keeps[s] = true
|
||||
}
|
||||
var problems []string
|
||||
for _, sr := range r.Shape.Reads(c.Data) {
|
||||
@@ -5118,10 +5120,7 @@ func trafficProblems(m catalogue.Manifest, s catalogue.SeatDeclaration) []string
|
||||
m.Module, s.Name))
|
||||
}
|
||||
for _, r := range s.Records {
|
||||
kept := false
|
||||
for _, st := range m.State {
|
||||
kept = kept || st.Name == r
|
||||
}
|
||||
kept := slices.Contains(catalogue.KeptStates(m), r) // either form (issue 1966)
|
||||
if !kept {
|
||||
problems = append(problems, fmt.Sprintf(
|
||||
"%s says %s's users read its records %q, which it keeps no state of", m.Module, s.Name, r))
|
||||
|
||||
@@ -1403,9 +1403,12 @@ func caseAModuleOffersItsOwnStateOnly(t *testing.T) {
|
||||
t.Errorf("%s: accepted, or refused without %q: %v", raw, want, err)
|
||||
}
|
||||
}
|
||||
ok := `{"module":"power","state":["draw"],"contributions":[` + fmt.Sprintf(block, "power.draw") + `]}`
|
||||
if _, err := ParseManifest([]byte(ok)); err != nil {
|
||||
t.Errorf("its own state was refused: %v", err)
|
||||
// Issue 1966: its own state in either form, the old section's or a key-value entry of `requires` (ADR 0595 §11).
|
||||
for _, ok := range []string{`{"module":"power","state":["draw"],"contributions":[` + fmt.Sprintf(block, "power.draw") + `]}`,
|
||||
`{"module":"power","requires":[{"name":"draw","storage":"key-value","template":"state"}],"contributions":[` + fmt.Sprintf(block, "power.draw") + `]}`} {
|
||||
if _, err := ParseManifest([]byte(ok)); err != nil {
|
||||
t.Errorf("its own state was refused: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4735,6 +4738,11 @@ func caseTheNewRulesAreHeldToWhatTheSeatSays(t *testing.T) {
|
||||
t.Errorf("not refused: %q in %s", want, got)
|
||||
}
|
||||
}
|
||||
// Issue 1966: records kept as a key-value entry of `requires` are kept state, as the old section's are.
|
||||
m.BusState = []catalogue.BusStateEntry{{Name: "nothing", Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState}}
|
||||
if got := strings.Join(declaredSeatProblems(m), "; "); strings.Contains(got, "keeps no state of") {
|
||||
t.Errorf("records kept in requires refused: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
// **A build machine has no store, so it may not judge a seat.** The set is data the control plane
|
||||
|
||||
Reference in New Issue
Block a user