why

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package why implements `caesium why <run> --task <t>` (data-plane-memory A3): the causal explainer for why a task in a run executed, hit the cache, or re-ran. It calls the server's GET /v1/jobs/:id/runs/:run_id/why?task=<t> endpoint and renders either a human-readable summary table (default) or the raw machine-readable JSON (--json), so the explanation can be both eyeballed and asserted in a harness.

On a FANNED step (dynamic fan-out) `--task` alone names N task instances, not one, so the server answers with a group summary — partition count, status histogram, the first failed partition's cause, and the aggregate timing — and `--partition <value>` selects a single instance for the full per-instance explanation.

Index

Constants

This section is empty.

Variables

View Source
var Cmd = &cobra.Command{
	Use:   "why <run-id> --task <task> --job-id <job-id> [--partition <value>]",
	Short: "Explain why a task ran, hit the cache, or re-ran",
	Long: "Explain why a specific task in a run executed, was served from cache, " +
		"or re-ran — by diffing the task's persisted identity-hash inputs against " +
		"the prior/cached run and naming the discriminating field(s). Prints a " +
		"human-readable summary by default, or machine-readable JSON with --json. " +
		"A fanned step answers with the group summary (partition count, status " +
		"histogram, first failure); pass --partition <value> for one instance.",
	Args: cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		runID := strings.TrimSpace(args[0])
		if whyJobID == "" {
			return fmt.Errorf("--job-id is required")
		}
		if whyTask == "" {
			return fmt.Errorf("--task is required")
		}

		server := strings.TrimSuffix(whyServer, "/")
		query := url.Values{}
		query.Set("task", whyTask)
		if partition := strings.TrimSpace(whyPartition); partition != "" {
			query.Set("partition", partition)
		}
		reqURL := fmt.Sprintf("%s/v1/jobs/%s/runs/%s/why?%s",
			server, whyJobID, runID, query.Encode())

		req, err := http.NewRequestWithContext(cmd.Context(), http.MethodGet, reqURL, nil)
		if err != nil {
			return err
		}
		if apiKey := resolveAPIKey(cmd, whyAPIKey); apiKey != "" {
			req.Header.Set("Authorization", "Bearer "+apiKey)
		}

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			return err
		}
		defer func() { _ = resp.Body.Close() }()

		body, _ := io.ReadAll(resp.Body)
		if resp.StatusCode >= http.StatusBadRequest {
			return fmt.Errorf("why failed (%d): %s", resp.StatusCode, strings.TrimSpace(string(body)))
		}

		stdout := cmd.OutOrStdout()
		if whyJSON {
			// Re-indent for readability; fall back to the raw body if it isn't
			// JSON (it always should be).
			var out any
			if err := json.Unmarshal(body, &out); err != nil {
				_, _ = stdout.Write(body)
				return nil
			}
			pretty, _ := json.MarshalIndent(out, "", "  ")
			_, _ = stdout.Write(pretty)
			_, _ = fmt.Fprintln(stdout)
			return nil
		}

		var exp explanation
		if err := json.Unmarshal(body, &exp); err != nil {

			_, _ = stdout.Write(body)
			return nil
		}
		renderTable(cmd, &exp)
		return nil
	},
}

Cmd is the `caesium why` command.

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL