atvm: preserve authoritative host results in watcher artifacts
Prefer failing and terminal host results when merging supplemental subrun artifacts so a later partial artifact cannot overwrite a more authoritative outcome. Also point ATVM agent guidance at the ATVM-specific git guide and add that guide to document draft-only commit handling and the default SSH command pattern.
This commit is contained in:
@@ -66,7 +66,7 @@ This file defines how to operate and maintain the ATVM workspace in `/home/aw/co
|
|||||||
- Never execute setup or automation commands that require approval until the operator explicitly approves them.
|
- Never execute setup or automation commands that require approval until the operator explicitly approves them.
|
||||||
- For ATVM run approvals, treat `approve` as run-with-watcher and `approve without watcher` as run-without-watcher.
|
- For ATVM run approvals, treat `approve` as run-with-watcher and `approve without watcher` as run-without-watcher.
|
||||||
- Treat git/commit requests as a separate approval gate.
|
- Treat git/commit requests as a separate approval gate.
|
||||||
- Follow `/home/aw/code/cds/git-guide.md` for commit-request handling, including the rule that phrases such as `create me a git`, `create a git`, `create a git description`, `make me a git`, `make a git`, `make me a git description`, `create me a git description`, and close variations are prepare-only until the operator explicitly approves the displayed commit command.
|
- Follow `/home/aw/code/cds/atvm/git-guide.md` for ATVM git command drafting and commit-request handling, including the default controller repo, SSH command prefix, and the rule that phrases such as `create me a git`, `create a git`, `create a git description`, `make me a git`, `make a git`, `make me a git description`, `create me a git description`, and close variations are prepare-only until the operator explicitly approves the displayed commit command.
|
||||||
- Never execute `git push` from the assistant for this workspace.
|
- Never execute `git push` from the assistant for this workspace.
|
||||||
- After creating a local commit, stop and give the operator the exact manual push command reference, defaulting to `git push origin main` unless they explicitly ask for a different remote or branch.
|
- After creating a local commit, stop and give the operator the exact manual push command reference, defaulting to `git push origin main` unless they explicitly ask for a different remote or branch.
|
||||||
- Do not treat `approve` after a commit as permission to push; pushing requires separate explicit wording and still remains manual-reference-only unless the operator explicitly overrides this workspace rule.
|
- Do not treat `approve` after a commit as permission to push; pushing requires separate explicit wording and still remains manual-reference-only unless the operator explicitly overrides this workspace rule.
|
||||||
|
|||||||
62
atvm/git-guide.md
Normal file
62
atvm/git-guide.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Git Guide
|
||||||
|
|
||||||
|
This file records ATVM-specific git workflow preferences for `/home/aw/code/cds/atvm`.
|
||||||
|
|
||||||
|
## Repository Reference
|
||||||
|
- For ATVM git command drafting, assume the primary operator-managed repo is `/root/cdc-e2e-cyp-12.17.4` unless the operator explicitly says otherwise.
|
||||||
|
|
||||||
|
## Execution Rule
|
||||||
|
- For this ATVM workspace, do not automatically perform any git-related command.
|
||||||
|
- Do not run `git status`, `git add`, `git commit`, `git push`, `git pull`, `git fetch`, `git stash`, `git checkout`, `git switch`, `git rebase`, `git merge`, `git diff`, or any other git command unless the operator explicitly asks for that exact command to be executed.
|
||||||
|
- By default, git requests in this workspace are draft-only requests.
|
||||||
|
- Respond by preparing the exact commands for operator review, not by executing them.
|
||||||
|
- Always write the drafted ATVM git commands to `/tmp/commit.txt` so the operator can copy and paste them.
|
||||||
|
- Assume the operator will always run ATVM git commands manually.
|
||||||
|
|
||||||
|
## SSH Default
|
||||||
|
- When drafting git commands for the controller repo and SSH-backed git access is needed, use this exact prefix:
|
||||||
|
`GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_anthony -o IdentitiesOnly=yes'`
|
||||||
|
- Prefer complete copy-pasteable command sequences that include that prefix for `git fetch`, `git pull`, and `git push` examples when applicable.
|
||||||
|
|
||||||
|
## Commit Message Requests
|
||||||
|
- If the operator asks for a git commit description, draft the proposed commit message first.
|
||||||
|
- When warranted by the size or complexity of the change, provide both:
|
||||||
|
- a concise commit title/summary line
|
||||||
|
- a detailed commit description/body listing the key changes
|
||||||
|
- The proposed `git commit` command should match the full proposed message, including the detailed body when one is warranted.
|
||||||
|
- After the proposed commit message, show the exact `git commit` command that would be used.
|
||||||
|
- Write the proposed ATVM git commands to `/tmp/commit.txt`.
|
||||||
|
- If the operator asks for a git commit, do not commit immediately.
|
||||||
|
- First show both:
|
||||||
|
- the proposed commit description/message
|
||||||
|
- the exact `git commit` command planned for execution
|
||||||
|
- When a detailed body is warranted, do not reduce the proposed commit to only the short title at execution time.
|
||||||
|
- Do not run `git commit` immediately after drafting the message.
|
||||||
|
- Wait for explicit user approval before creating the commit.
|
||||||
|
- Do not treat a request such as "give me the git commit" or "make the commit" as approval by itself.
|
||||||
|
- Do not treat a request such as "create a git for me", "show me a proposed git commit", "prepare the commit", or any similar commit-related wording as approval by itself.
|
||||||
|
- Treat all of the following as approval-gated prepare-only requests, not as permission to run `git commit`:
|
||||||
|
- `create me a git`
|
||||||
|
- `create a git`
|
||||||
|
- `create a git description`
|
||||||
|
- `make me a git`
|
||||||
|
- `make a git`
|
||||||
|
- `make me a git description`
|
||||||
|
- `create me a git description`
|
||||||
|
- Treat close variations of those phrases with the same intent the same way.
|
||||||
|
- If the request means "prepare or create git/commit wording or a commit", ask for approval first before running any commit action.
|
||||||
|
- Treat every commit-related request as prepare-and-show-only until the operator explicitly approves the commit after seeing the proposed message or exact command.
|
||||||
|
- Only execute `git commit` after the operator explicitly approves the displayed commit command.
|
||||||
|
- If there is any ambiguity about whether the operator is asking for preparation versus execution, default to not committing.
|
||||||
|
|
||||||
|
## Push Requests
|
||||||
|
- For this workspace, never execute `git push` from the assistant.
|
||||||
|
- When the operator asks to push, show the exact push command only.
|
||||||
|
- Default push command:
|
||||||
|
`GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519_anthony -o IdentitiesOnly=yes' git push origin main`
|
||||||
|
- When reminding the operator about the push command after a commit proposal or completed commit, display that full SSH-prefixed command unless they explicitly ask for a different remote, branch, or SSH pattern.
|
||||||
|
- Write the proposed push command to `/tmp/commit.txt`.
|
||||||
|
|
||||||
|
## Commit Scope
|
||||||
|
- When committing, include only the files relevant to the approved change.
|
||||||
|
- Leave unrelated worktree changes uncommitted unless the operator explicitly asks to include them.
|
||||||
@@ -1668,6 +1668,39 @@ def merge_categorized_state(
|
|||||||
existing["state"] = state
|
existing["state"] = state
|
||||||
|
|
||||||
|
|
||||||
|
def merge_host_results_prefer_authoritative(
|
||||||
|
base_results: Dict[str, HostResult],
|
||||||
|
supplemental_results: Dict[str, HostResult],
|
||||||
|
) -> Dict[str, HostResult]:
|
||||||
|
merged = dict(base_results)
|
||||||
|
for host, candidate in supplemental_results.items():
|
||||||
|
existing = merged.get(host)
|
||||||
|
if existing is None:
|
||||||
|
merged[host] = candidate
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Never let a supplemental artifact overwrite a known failure with PASS.
|
||||||
|
if existing.failures and not candidate.failures:
|
||||||
|
continue
|
||||||
|
if candidate.failures and not existing.failures:
|
||||||
|
merged[host] = candidate
|
||||||
|
continue
|
||||||
|
|
||||||
|
existing_terminal = existing.status in {"PASS", "FAIL"}
|
||||||
|
candidate_terminal = candidate.status in {"PASS", "FAIL"}
|
||||||
|
if existing_terminal and not candidate_terminal:
|
||||||
|
continue
|
||||||
|
if candidate_terminal and not existing_terminal:
|
||||||
|
merged[host] = candidate
|
||||||
|
continue
|
||||||
|
|
||||||
|
existing_ts = existing.timestamp or datetime.fromtimestamp(0, tz=timezone.utc)
|
||||||
|
candidate_ts = candidate.timestamp or datetime.fromtimestamp(0, tz=timezone.utc)
|
||||||
|
if candidate_ts >= existing_ts:
|
||||||
|
merged[host] = candidate
|
||||||
|
return merged
|
||||||
|
|
||||||
|
|
||||||
def extract_segment_build_name(segment_text: str, parent_build_name: str) -> Optional[str]:
|
def extract_segment_build_name(segment_text: str, parent_build_name: str) -> Optional[str]:
|
||||||
patterns = [
|
patterns = [
|
||||||
rf"({re.escape(parent_build_name)}-[A-Za-z0-9_.-]*batch\d+_\d+)",
|
rf"({re.escape(parent_build_name)}-[A-Za-z0-9_.-]*batch\d+_\d+)",
|
||||||
@@ -1856,9 +1889,10 @@ def discover_categorized_subruns(
|
|||||||
run_ended_at=check_ts + timedelta(seconds=5),
|
run_ended_at=check_ts + timedelta(seconds=5),
|
||||||
)
|
)
|
||||||
if group_host_results:
|
if group_host_results:
|
||||||
merged_results = dict(host_results)
|
host_results = merge_host_results_prefer_authoritative(
|
||||||
merged_results.update(group_host_results)
|
host_results,
|
||||||
host_results = merged_results
|
group_host_results,
|
||||||
|
)
|
||||||
completed_hosts.extend([host for host in host_results if host not in completed_hosts])
|
completed_hosts.extend([host for host in host_results if host not in completed_hosts])
|
||||||
|
|
||||||
if not host_results and check_ts:
|
if not host_results and check_ts:
|
||||||
|
|||||||
Reference in New Issue
Block a user