View reads the indexer's published packages with indexer_packages
A module's fingerprint takes the digests of the packages its last build imported, so the published packages say why a merge moved a module or not; the state needs a read tool like every other (ADR 0593 §2; D2). Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -124,6 +124,24 @@ func Tools(r view.Reader, u view.UsageReader) []stdio.Tool {
|
||||
key, _ := args["key"].(string)
|
||||
return view.ControlRecord(r.ConfigCandidatesState, delivery.IndexerConfigCandidatesState, key)
|
||||
}},
|
||||
{Name: view.PackagesReadTool,
|
||||
Description: "The mesh packages as the indexer publishes them (novox/hq ADR 0593 §2): per mesh Go module (its module " +
|
||||
"path, such as git.novox.be/novox/mesh-sdk/go), the trunk merge that published it (the version a build pins), the " +
|
||||
"digest of its go.mod and go.sum, and the content digest of each package in it. A module's fingerprint takes the " +
|
||||
"digests of the packages its last build imported, so this says why a package merge moved a module or not. Give " +
|
||||
"module for one. Read-only.",
|
||||
Input: map[string]any{"type": "object", "properties": map[string]any{
|
||||
"module": map[string]any{"type": "string", "description": "one mesh Go module's path"}}},
|
||||
Run: func(args map[string]any) (any, error) {
|
||||
key := ""
|
||||
if module, _ := args["module"].(string); strings.TrimSpace(module) != "" {
|
||||
var err error
|
||||
if key, err = delivery.PackagesKey(strings.TrimSpace(module)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return view.ControlRecord(r.PackagesState, delivery.PackagesState, key)
|
||||
}},
|
||||
{Name: view.CandidatesReadTool,
|
||||
Description: "Every candidate the indexer holds, by group, each as stored under candidates.<group>; with module, only those with a " +
|
||||
"pull request touching that module. Keys that cannot be read are listed as unreadable. Read-only.",
|
||||
@@ -288,6 +306,7 @@ func main() {
|
||||
PresenceState: read(stdio.State(view.StatusPresenceState)), StuckState: read(stdio.State(view.StatusStuckState)),
|
||||
PredefinedState: read(stdio.State(delivery.IndexerModule + "." + delivery.IndexerPredefinedState)),
|
||||
ConfigCandidatesState: read(stdio.State(delivery.IndexerModule + "." + delivery.IndexerConfigCandidatesState)),
|
||||
PackagesState: read(stdio.State(delivery.IndexerModule + "." + delivery.PackagesState)),
|
||||
BuildLog: stdio.Log(delivery.BuildLogRead).Since}
|
||||
u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")),
|
||||
Steps: map[string]view.StateRead{}, Pauses: map[string]view.StateRead{}, Backlog: backlogOf(socket())}
|
||||
|
||||
@@ -548,3 +548,23 @@ func TestAssignerDifferencesAndNodeHavesToolsAnswerAsStored(t *testing.T) {
|
||||
t.Errorf("the values were read one at a time (at most %d in flight)", slow.maxFlight.Load())
|
||||
}
|
||||
}
|
||||
|
||||
// ADR 0593 §2 (D2): indexer_packages answers the indexer's published packages, one Go module by its path or all.
|
||||
func TestPackagesToolAnswersThePublishedModules(t *testing.T) {
|
||||
key, err := delivery.PackagesKey("git.novox.be/novox/mesh-sdk/go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
const value = `{"v":1,"module":"git.novox.be/novox/mesh-sdk/go","commit":"c1"}`
|
||||
r := view.Reader{PackagesState: fake{key: value}.reader().State}
|
||||
out, err := run(t, r, view.PackagesReadTool, map[string]any{"module": "git.novox.be/novox/mesh-sdk/go"})
|
||||
if err != nil || string(out.(json.RawMessage)) != value {
|
||||
t.Fatalf("one module: %v %v", out, err)
|
||||
}
|
||||
if all, err := run(t, r, view.PackagesReadTool, nil); err != nil || all.(map[string]any)["holds"] != 1 {
|
||||
t.Errorf("every module: %v %v", all, err)
|
||||
}
|
||||
if _, err := run(t, r, view.PackagesReadTool, map[string]any{"module": "github.com/x/y"}); err == nil {
|
||||
t.Error("a path that is no mesh Go module's was read")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ type Reader struct {
|
||||
ConditionsState, AttemptsState, PresenceState, StuckState StateRead
|
||||
// PredefinedState and ConfigCandidatesState are the indexer's control records (ADR 0565 §2, §15); unset reads none.
|
||||
PredefinedState, ConfigCandidatesState StateRead
|
||||
// PackagesState is the indexer's published packages (delivery.PackagesBucket, ADR 0593 §2); unset reads none.
|
||||
PackagesState StateRead
|
||||
// BuildLog reads the builder's log from a time (stdio.Log(delivery.BuildLogRead).Since); unset reads none.
|
||||
BuildLog LogSince
|
||||
}
|
||||
@@ -64,6 +66,8 @@ type LogSince func(at time.Time, keys string, limit int) (*stdio.LogPage, error)
|
||||
const (
|
||||
PredefinedReadTool = "indexer_predefined"
|
||||
ConfigCandidatesReadTool = "indexer_config_candidates"
|
||||
// PackagesReadTool reads the indexer's published packages (ADR 0593 §2): what a fingerprint takes of a mesh package.
|
||||
PackagesReadTool = "indexer_packages"
|
||||
)
|
||||
|
||||
// ControlRecord is every key of one of the indexer's control records as stored, or one key, with how many it holds.
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
|
||||
if m.Module != "mesh-delivery-view" {
|
||||
t.Errorf("module = %q", m.Module)
|
||||
}
|
||||
want := []string{"mesh-build-go.pauses", "mesh-build-go.steps", "mesh-build-image.pauses", "mesh-build-image.steps", "mesh-build-node.pauses", "mesh-build-node.steps", "mesh-conditions.conditions", "mesh-config.resolved", "mesh-delivery-assigner.asks", "mesh-delivery-assigner.differences", "mesh-delivery-assigner.placement", "mesh-delivery-assigner.wants", "mesh-delivery-builder.build-log", "mesh-delivery-builder.builds", "mesh-delivery-checker.tries", "mesh-delivery-gate.asks", "mesh-delivery-gate.source", "mesh-delivery-indexer.candidates", "mesh-delivery-indexer.config-candidates", "mesh-delivery-indexer.heard", "mesh-delivery-indexer.modules", "mesh-delivery-indexer.predefined", "mesh-delivery-indexer.taken", "mesh-delivery-teller.answers", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-vault.signers", "node-engine.have"} // view_status reads the keeper's conditions and the healers' attempts (1952/V1); build_usage reads the build modules' steps and pauses, mesh-config's capacities and the checker's tries; 1168/AC1, 1241/AC4, 1345/AC3, 1297/B8, B9
|
||||
want := []string{"mesh-build-go.pauses", "mesh-build-go.steps", "mesh-build-image.pauses", "mesh-build-image.steps", "mesh-build-node.pauses", "mesh-build-node.steps", "mesh-conditions.conditions", "mesh-config.resolved", "mesh-delivery-assigner.asks", "mesh-delivery-assigner.differences", "mesh-delivery-assigner.placement", "mesh-delivery-assigner.wants", "mesh-delivery-builder.build-log", "mesh-delivery-builder.builds", "mesh-delivery-checker.tries", "mesh-delivery-gate.asks", "mesh-delivery-gate.source", "mesh-delivery-indexer.candidates", "mesh-delivery-indexer.config-candidates", "mesh-delivery-indexer.heard", "mesh-delivery-indexer.modules", "mesh-delivery-indexer.packages", "mesh-delivery-indexer.predefined", "mesh-delivery-indexer.taken", "mesh-delivery-teller.answers", "mesh-delivery-watchman.presence", "mesh-delivery-watchman.stuck", "mesh-healers.attempts", "mesh-vault.signers", "node-engine.have"} // view_status reads the keeper's conditions and the healers' attempts (1952/V1); build_usage reads the build modules' steps and pauses, mesh-config's capacities and the checker's tries; 1168/AC1, 1241/AC4, 1345/AC3, 1297/B8, B9
|
||||
got := slices.Clone(m.Reads)
|
||||
slices.Sort(got)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
@@ -119,7 +119,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", "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"}; !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"}; !reflect.DeepEqual(m.Tools, want) {
|
||||
t.Errorf("tools = %v, want %v", m.Tools, want)
|
||||
}
|
||||
for _, a := range m.Build.Artifacts {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"indexer_candidates",
|
||||
"indexer_predefined",
|
||||
"indexer_config_candidates",
|
||||
"indexer_packages",
|
||||
"builder_build",
|
||||
"builder_builds",
|
||||
"builder_history",
|
||||
@@ -55,6 +56,7 @@
|
||||
"mesh-delivery-indexer.config-candidates",
|
||||
"mesh-delivery-indexer.heard",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"mesh-delivery-indexer.packages",
|
||||
"mesh-delivery-indexer.predefined",
|
||||
"mesh-delivery-indexer.taken",
|
||||
"mesh-delivery-teller.answers",
|
||||
|
||||
Reference in New Issue
Block a user