Skip to content

Fix field mode derivation and metadata refresh handling - #9

Merged
someson merged 12 commits into
mainfrom
claude/wizardly-cori-v71gj6
Sep 26, 2026
Merged

someson merged 12 commits into
mainfrom
claude/wizardly-cori-v71gj6

Conversation

@someson

@someson someson commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Summary

This PR fixes two related issues in the form UI: field mode is now correctly derived from typed values rather than persisting previous modes, and stale metadata entries now trigger background refresh to keep the cache current.

Key Changes

Field Mode Derivation (typed_value_test.go)

  • Added comprehensive test coverage for field mode derivation from typed values
  • Field mode is now determined by the content being edited, not preserved from before
  • Typing $RG into a literal field correctly switches it to var mode
  • Typing a literal with spaces into a var field correctly switches it to literal mode
  • Command substitutions like $(cat name.txt) are recognized as var mode

Metadata Refresh Handling (refresh_test.go, model.go)

  • Added refresh callback to MetadataLoadedMsg for stale cache entries
  • Stale metadata now automatically triggers background refresh via refreshMetadata()
  • Fresh metadata entries do not trigger unnecessary refresh
  • Refresh runs with a 30-second timeout and errors are not surfaced to the user
  • New metadataRefreshedMsg type reports completion of background refresh

Pre-fill Logic (prefill.go)

  • Changed fillability check from Source == FieldSourceNone to new fillable() function
  • Fields holding only their metadata default are now considered fillable
  • This allows Azure defaults, environment matches, and drafts to override metadata defaults
  • Updated comments to clarify the pre-fill priority order per spec §8.5

Validation and Rendering

  • Fixed escape validation to only check enabled fields
  • Improved needsQuoting() to handle shell metacharacters: #, ~, {, }, ^
  • Updated README examples to show correct quoting (var refs like $RG no longer unnecessarily quoted)

Metadata Parsing Improvements

  • Added detection for "separated by spaces" pattern in help text for list value kind inference
  • Fixed help text parsing in baseline metadata (removed erroneous line breaks)
  • Corrected takes_value flags for several parameters (e.g., --enable-local-user, --accept-system-assigned-identities)

Environment Variable Matching (vars/match.go)

  • Fixed suffix matching to require separator before suffix (e.g., USERNAME no longer matches --name)
  • Added test coverage for this edge case

Installation Script (install.sh)

  • Updated to properly mirror Go-side state and cache directory logic
  • Added state_dir() and cache_dir() functions respecting XDG standards and macOS conventions
  • Clarified that --purge removes both state and cache directories

Notable Implementation Details

  • The fillable() helper function encapsulates the logic for determining which fields can be pre-filled
  • Background refresh is non-blocking and doesn't interrupt the user's current form session
  • Mode derivation happens during field editing, allowing dynamic switching based on content

https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q

…and stale refresh

- Editing a field (and restoring a draft) kept the previous mode, so a
  typed $RG rendered as '$RG' and a var field edited to "my group"
  was emitted unquoted. The mode is now derived from the value.
- Fields holding only their metadata default were skipped by the draft,
  bindings, env and Azure-defaults stages, inverting spec §8.5.
- Stale cache entries (and the embedded baseline) were never refreshed:
  Result.Refresh had no caller. It now runs in the background.
- undefined-var and escape-error no longer block Done for disabled fields.
- Ctrl+G insert spliced by byte offset using a rune cursor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
…itch names

az wraps help at hyphens, so 'comma-separated' became 'comma- separated'
and 'Values from: az account list-locations' became an unrunnable
'list- locations'. aks create --enable-addons was misread as a switch.

--identity, --assign-identity and --service-principal take values on most
commands (acr/aks/appgw/postgres/...); login's switch forms are already
recognised from their help text. Goldens and baseline regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
Unquoted they trigger comments, tilde/brace expansion or zsh globbing
and '=cmd' expansion, so az would not receive the value as typed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
The check ran on the separator-folded name, so USERNAME, HOSTNAME and
LOGNAME all bound to --name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
With the widget's usual end-of-line cursor, 'az a && az b' opened the
form for the first command instead of the one being typed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
…dirs

--purge was documented but only PURGE_STATE=1 worked, and the purge path
ignored XDG_STATE_HOME and macOS locations used by the binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
…mmand

Flags the metadata does not know (outdated cache, extensions) were
silently dropped on Done; they are now re-emitted exactly as typed.
A value-taking flag typed with no value (vm create --assign-identity)
is emitted bare while its field stays empty instead of disappearing.
escape-error is now a warning: literal values are always single-quoted,
so an unbalanced quote reaches az intact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
- Enter on a field with fetched values opens a picker (first row: type
  a value manually); before, they were only counted as "(N options)".
- Only the first command of a multi-command hint is run, punctuation
  and placeholders are handled, and commands that need context
  (vm list-sizes, aks get-versions/get-upgrades) get the form's
  --location / --resource-group / --name; edits to those drop stale
  choices.
- Output parsing is deterministic and understands version keys and
  plain string arrays; error text is truncated on rune boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
deb/rpm ship az as a launcher in /usr/bin, so the install root resolved
to /usr, whose mtime never changes on upgrade; pip venv roots behave
the same. Follow the launcher to the Python it runs and use the newest
site-packages mtime, which changes when azure_cli-*.dist-info is
renamed. Also recognise /usr/lib64/az.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
zsh CURSOR and bash 5 READLINE_POINT count characters while the
tokenizer uses bytes, so non-ASCII text before the cursor picked the
wrong command. The widgets now pass the text left of the cursor
(--cursor-prefix). An unclosed $(az … or `az … no longer gains a
closing delimiter when the line is rebuilt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
- update: SemVer precedence, so 1.0.0-rc1 users are told about 1.0.0.
- debug: Close no longer races with background Event calls.
- lock: fall back to a private per-user dir instead of shared /tmp,
  refuse symlinks, and re-check the locked inode to close the
  flock/unlink race; fix the outdated package comment.
- diagnostics: stop rewriting parse-health.log on every append once it
  holds 200 entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
The e2e tests ran azform against the shared default state dir. The
bash test cancels 'az group create', saving a draft that carries env
matches from the runner (--name $RUNNER_NAME); the zsh round-trip
test then restored it and appended its input to it. With drafts now
restored in var mode, '$RUNNER_NAMEwesteurope' is an undefined var
and Done is blocked, so azform never exited. Each test now uses a
private state dir. The zsh tests also called cmd.Wait twice, which the
race detector flagged on the failure path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dza8X5c3XGHUjejpqGLR8q
@someson
someson merged commit e196acc into main Sep 26, 2026
6 checks passed
@someson
someson deleted the claude/wizardly-cori-v71gj6 branch September 26, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants