Skip to content

feat: surface execution observations in task run + add axis observations CLI#139

Merged
toasterbook88 merged 2 commits into
mainfrom
obs-surface-and-cli
May 23, 2026
Merged

feat: surface execution observations in task run + add axis observations CLI#139
toasterbook88 merged 2 commits into
mainfrom
obs-surface-and-cli

Conversation

@toasterbook88
Copy link
Copy Markdown
Owner

Post-execution measurement infrastructure already records peak RAM, wall time, and success status to state.json via RecordObservation. This change makes that data visible to operators.

Changes

  • Add PeakRAMMB, PeakVRAMMB, WallTimeMS to GuardedExecutionResult
  • Populate fields in runLocal/runRemote success and failure paths
  • Mirror fields in RunResponse for API serialization
  • Add formatObservationSummary helper; print after task run
  • Add axis observations command with list and inspect subcommands
  • Read from local state.json; show table, JSON, or detailed view
  • Add 10 unit tests for the observations CLI surface

Quality Gates

  • make lint: pass
  • make test-race: pass
  • make coverage: 72.5% (all gates met)
  • make build: pass

…ons CLI

Post-execution measurement infrastructure already records peak RAM,
wall time, and success status to state.json via RecordObservation.
This change makes that data visible to operators.

Changes:
- Add PeakRAMMB, PeakVRAMMB, WallTimeMS to GuardedExecutionResult
- Populate fields in runLocal/runRemote success and failure paths
- Mirror fields in RunResponse for API serialization
- Add formatObservationSummary helper; print after task run
- Add axis observations command with list and inspect subcommands
- Read from local state.json; show table, JSON, or detailed view
- Add 10 unit tests for the observations CLI surface

Quality gates: lint, test-race, coverage (72.5%), build all pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@toasterbook88 toasterbook88 added the enhancement New feature or request label May 23, 2026
@toasterbook88 toasterbook88 enabled auto-merge (squash) May 23, 2026 00:39
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@toasterbook88 toasterbook88 merged commit 6fe0bbe into main May 23, 2026
8 checks passed
@toasterbook88 toasterbook88 deleted the obs-surface-and-cli branch May 23, 2026 00:44
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new observations command to the axis CLI, enabling users to list and inspect execution performance metrics such as wall time, RAM, and VRAM usage. It also updates the task execution logic to capture and display these metrics upon completion. Key feedback includes optimizing map lookups for efficiency, addressing non-deterministic behavior in prefix-based lookups caused by Go's map iteration order, and refining table formatting and code readability.

Comment thread cmd/axis/observations.go
Comment on lines +177 to +183
for k, obs := range st.Observations {
if k == key {
obsCopy := obs
found = &obsCopy
break
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This loop is unnecessary for an exact key lookup in a map. You can directly access the element using the key, which is more efficient ($O(1)$ vs $O(N)$).

if obs, ok := st.Observations[key]; ok {
	obsCopy := obs
	found = &obsCopy
}

Comment thread cmd/axis/observations.go
Comment on lines +186 to +192
for k, obs := range st.Observations {
if strings.HasPrefix(k, key) {
obsCopy := obs
found = &obsCopy
break
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Iterating over a map to find a prefix match is non-deterministic in Go because map iteration order is randomized. If multiple keys share the same prefix, the command will return a different observation each time it is run. Consider collecting all matches and returning an error if more than one is found, or sorting the keys before matching to ensure determinism.

Comment thread cmd/axis/observations.go
Comment on lines +221 to +224
if !state.ObservationIsFresh(*found, time.Now().UTC()) {
isStale = " (stale)"
}
fmt.Fprintf(out, "Fresh: %v%s\n", state.ObservationIsFresh(*found, time.Now().UTC()), isStale)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function state.ObservationIsFresh is called twice with the same arguments. You can reuse the result of the first call to improve readability and slightly reduce overhead.

isFresh := state.ObservationIsFresh(*found, time.Now().UTC())
isStale := ""
if !isFresh {
	isStale = " (stale)"
}
fmt.Fprintf(out, "Fresh:       %v%s\n", isFresh, isStale)

Comment thread cmd/axis/observations.go
Comment on lines +62 to +63
ui.WhiteColor.Fprintf(&b, " %-15s %-12s %-12s %-12s %10s %10s %8s %8s\n",
"NODE", "WORKLOAD", "BACKEND", "TOOL", "WALL MS", "PEAK RAM", "PEAK VRAM", "SAMPLES")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The header PEAK VRAM is 9 characters long, but the format specifier %8s is used. This will cause the column to be at least 9 characters wide anyway, potentially misaligning it with the data rows if they strictly follow the 8-character width. Additionally, for clarity, it would be beneficial to include units (MB) in the PEAK RAM header or values, similar to how VRAM is handled. Furthermore, per repository guidelines, if this list of observations can become excessively long, it should be truncated with an indication of the remaining count.

References
  1. When displaying a list of items in a user-facing message (e.g., warnings, logs), truncate the list if it can become excessively long and indicate that it has been truncated, for example by showing a count of the remaining items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant