Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/skills/orch/schemas/dev-return.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Fix rounds have an input-side sibling bound by the same token, `tmp/dev-round-[I
| `branch` | Yes | `--branch` | Git branch (non-empty string) |
| `commit` | Yes | `--commit` | HEAD SHA after the commit, or the prior HEAD when no commit was needed |
| `baseline_lines` | implement | measured by writer | Additions plus deletions against the base branch at `commit`, omitting binary rows and render mirrors whose source changed in the same diff, floored at 1. **Absent for `fix`** |
| `validate` | Yes | `--validate` | `pass`, `no-verdict` or `FAILING: check1,check2` — a closed enumeration. With `--validate-run-dir`, `pass` needs a local run that passed or a `ci` record whose verdict is `pending`; with `ci`, it accepts the local edits and leaves required CI pending: the merge-group run proves the head where the record carries `ci-event=merge_group`, as every queue-only change's does, and a red one returns the change to its lane under [merge-pr.md § 5](../workflows/merge-pr.md#5-execute-the-merge) Recovery cycle. `no-verdict` needs a run that ended with that result (`--record` reads `verdict=no-verdict`); with `--validate-record`, `pass` needs exit status 0, and `no-verdict` is refused because the record carries no no-verdict marker; `FAILING` is accepted beside a run of any verdict, because it judges every gate of the round; a `fix` receipt's run must still belong to its round (see `validate_mode`). `dev-artifact-check` accepts `pass` and `no-verdict` and retries `FAILING` |
| `validate` | Yes | `--validate` | `pass`, `no-verdict` or `FAILING: check1,check2` — a closed enumeration. With `--validate-run-dir`, `pass` needs a local run that passed or a `ci` record whose verdict is `pending`; with `ci`, it accepts the local edits and leaves required CI pending: the merge-group run proves the head where the record carries `ci-event=merge_group`, as every queue-only change's does, and a red one returns the change to its lane under [merge-pr.md § 5](../workflows/merge-pr.md#5-execute-the-merge) Recovery cycle. `no-verdict` needs a run that ended with that result (`--record` reads `verdict=no-verdict`); `--validate-record` follows the [foreground record rule](#foreground-validation-record); `FAILING` is accepted beside a run of any verdict, because it judges every gate of the round; a `fix` receipt's run must still belong to its round (see `validate_mode`). `dev-artifact-check` accepts `pass` and `no-verdict` and retries `FAILING` |
| `validate_mode` | Yes | read from `--validate-run-dir` or `--validate-record` | The mode `dev-validate-run --record` reports for the run directory, or the `full` or `range` a [foreground validation record](#foreground-validation-record) states: `full`, the full invocation, which may execute scoped suites, `range`, a fix round's changes since its base, or `ci`, completed local edits with required CI pending. Where the project sets `DEV_VALIDATE_SELECTION_CMD`, a `ci` run first runs that selector's scoped suites, so a `ci` record can also carry `FAILING` or `no-verdict`. Implement and fix receipts accept `ci` only at the current HEAD. The runner's `head` is the HEAD at validation start, before the workflow commits. The runner's existing snapshot tree binds those pending contents to this receipt's committed `commit`; the writer refuses changed contents as `ci-contents-mismatch`. This receipt is no CI pass. Submit checks required pull-request CI. Its existing queue route proves required merge-group CI for queue-only work. `null` only beside a failing `validate` with no run, which omits both flags; a `pass` or `no-verdict` without the flag is refused. `dev-artifact-check` echoes it and refuses a missing key or any other value. A `fix` receipt names only a run or record that started at a HEAD containing its round record's `base_sha`, recording that base as `validate-base-orphaned`, or containing that base's rewritten SHA in the worktree-private `kendex-rebase-map` (ordered hops per [`workflow-state.md`](workflow-state.md), `rebase_map` row), no earlier than its `delegated_at`, and records the mode its round runs, `range`, or `full` where the project sets no `DEV_VALIDATE_RANGE_CMD`, or `ci`: the writer refuses an earlier round's run as `run-off-round` or `run-before-round`, and `dev-artifact-check` refuses any other mode as `mode_mismatch`. Submit accepts a current-head `ci` receipt as pending and reuses a `full` pass with no `validate_class_base`, or with `validate_selection` `battery` |
| `validate_time` | Yes | read from `--validate-run-dir` or `--validate-record` | The run's wall time as `dev-validate-run --record` reports it, or as the writer derives it from a record's two times: `started_at` and `ended_at` in UTC, and `seconds` between them. A `no-verdict` run carries one too, since a host or timeout result also ends the run. `null` where no run is named or the run is unfinished, so only beside a failing `validate`; a time beside a `null` `validate_mode` is refused. `dev-artifact-check` echoes it and refuses a missing key, a wrong type or seconds that are not the span; `dev-artifact-check` records it per round |
| `validate_lanes` | Optional | read from `--validate-run-dir` or `--validate-record` | Comma-separated lane names from the command's [output contract](../references/artifact-checks.md#validation-command-output). Absent when unreported, when the selection is the start's preview (the output contract's Missing or malformed last line row), or when no run is named. `dev-artifact-check` echoes it for round storage |
Expand Down Expand Up @@ -95,4 +95,4 @@ The Apple gate reads `ORCH_APPLE_WORKFLOW` and the space-separated `ORCH_APPLE_L

A project whose own policy runs its validation entry point in the foreground and forbids `dev-validate-run` names that run with `--validate-record FILE` in place of `--validate-run-dir`; the writer refuses the two together. FILE holds one `KEY=VALUE` per line: the mode, the HEAD the run started at, its UTC start and end, its exit status, and its lane selection with any lanes. `dev-return-write --help` gives the grammar, and the writer refuses a record that names no head, no time or no exit status.

The writer reads the record into the fields a run directory fills, so the receipt has the same shape on either route. It derives the wall time from the two times and the verdict from the exit status, `pass` for 0 and `FAILING` for any other. A `fix` receipt binds the record's head and start time to its round as it binds a run directory's. The record file stays where the project wrote it; the receipt does not copy its head or exit status.
The writer reads the record into the fields a run directory fills, so the receipt has the same shape on either route. It derives the wall time from the two times and reads the verdict through the runner's marker rule. An optional `verdict=no-verdict` carries that outcome with the same note and evidence requirements. Without the marker, exit 0 is `pass` and any other exit is `FAILING`. A `fix` receipt binds the record's head and start time to its round as it binds a run directory's. The record file stays where the project wrote it; the receipt does not copy its head or exit status.
27 changes: 16 additions & 11 deletions .agents/skills/orch/scripts/dev-return-write
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@
# the mode, the HEAD the run started at, its UTC start and end, its exit
# status and its lane selection. The writer reads it into the same fields a
# run directory fills and takes from it only what it states: the epoch start,
# the wall time and the verdict, pass for exit 0 and FAILING for any other,
# are derived here. A record carries no no-verdict marker, so it never carries a
# no-verdict. Every check below, the fix-round binding included, judges both
# routes alike.
# the wall time and the verdict are derived here. An optional verdict=no-verdict
# marker carries a timeout or unavailable host check, with the raw exit kept.
# The runner owns the marker's meaning. Every check below, the fix-round binding
# included, judges both routes alike.
#
# A fix round's run is bound to its round. The round record dev-round-write
# stamped at delegation, PATH/tmp/dev-round-ID-RID.json, names the round's
Expand Down Expand Up @@ -164,6 +164,8 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/branch-growth.sh"
# shellcheck source=lib/rebase-map.sh
source "$SCRIPT_DIR/lib/rebase-map.sh"
# shellcheck source=lib/validation-verdict.sh
source "$SCRIPT_DIR/lib/validation-verdict.sh"

# The Apple gate's trigger and its record. A changed path is Apple when one of
# its directory segments matches an APPLE_DIR_GLOBS glob, the way .gitignore
Expand Down Expand Up @@ -284,14 +286,16 @@ per line, each key once:
started-at=TIME when the run started, UTC YYYY-MM-DDTHH:MM:SSZ
ended-at=TIME when it ended, no earlier than started-at
exit=N the entry point's exit status, 0 to 999
verdict=no-verdict optional; the runner's timeout or host-check marker
selection=all|subset|battery|unreported
lanes=NAMES comma-separated, beside all, subset or battery only
selection and lanes are the validate: line of the validation command output
contract (references/artifact-checks.md). Every key but lanes is required.
contract (references/artifact-checks.md). Every key but lanes and verdict is required.
The writer derives the wall time from the two times and the verdict from the
exit status, pass for 0 and FAILING for any other, so the record never
carries a no-verdict; head and started-at bind a --kind fix receipt as a run
directory's do.
runner's marker rule. Without the marker, exit 0 is pass and any other exit is
FAILING. The marker preserves the raw exit and needs the same --validate-note
and evidence as a run directory. head and started-at bind a --kind fix receipt
as a run directory's do.
--summary TEXT embeds the summary inline; --summary-file PATH embeds a file's
content. --recovered-text PATH embeds the report round-recover read from a
stalled agent's transcript and records recovered_from: transcript. The three
Expand Down Expand Up @@ -480,13 +484,13 @@ done

# read_validate_record PATH — the foreground validation record --help gives the
# grammar of, read into the fields the run directory's --record line fills.
# The epoch start, the wall time and the verdict are derived here, never read.
# The epoch start and the wall time are derived here.
UTC_TIME='^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$'
record_value() { # PATH KEY VALUE PATTERN
[[ "$3" =~ $4 ]] || die validate-record-value "path=$1" "field=$2" "value=$3"
}
read_validate_record() {
local path="$1" line key value seen=" " line_no=0 exit_status="" epochs started ended
local path="$1" line key value seen=" " line_no=0 exit_status="" marker="" epochs started ended
[[ -f "$path" && -r "$path" ]] || die validate-record-unreadable "path=$path"
while IFS= read -r line || [[ -n "$line" ]]; do
line_no=$((line_no + 1))
Expand All @@ -500,6 +504,7 @@ read_validate_record() {
started-at) record_value "$path" "$key" "$value" "$UTC_TIME"; validate_started_at="$value" ;;
ended-at) record_value "$path" "$key" "$value" "$UTC_TIME"; validate_ended_at="$value" ;;
exit) record_value "$path" "$key" "$value" '^(0|[1-9][0-9]{0,2})$'; exit_status="$value" ;;
verdict) record_value "$path" "$key" "$value" '^no-verdict$'; marker=" $line" ;;
selection) record_value "$path" "$key" "$value" '^(all|subset|battery|unreported)$'; validate_selection="$value" ;;
# The lane grammar is the validation command output contract's.
lanes) record_value "$path" "$key" "$value" '^[[:alnum:]_.-]+(,[[:alnum:]_.-]+)*$'; validate_lanes="$value" ;;
Expand All @@ -523,7 +528,7 @@ read_validate_record() {
|| die validate-record-time "path=$path" "started-at=$validate_started_at" "ended-at=$validate_ended_at"
run_start="$started"
validate_seconds=$(( ended - started ))
if [[ "$exit_status" == 0 ]]; then run_verdict=pass; else run_verdict=FAILING; fi
run_verdict="$(validation_verdict "guard-exit=$exit_status at=$validate_ended_at$marker")"
}

# --- Validate required fields ---
Expand Down
9 changes: 3 additions & 6 deletions .agents/skills/orch/scripts/dev-validate-run
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ source "$SCRIPT_DIR/lib/job-unit.sh"
source "$SCRIPT_DIR/lib/gh-auth.sh"
# shellcheck source=lib/file-lock.sh
source "$SCRIPT_DIR/lib/file-lock.sh"
# shellcheck source=lib/validation-verdict.sh
source "$SCRIPT_DIR/lib/validation-verdict.sh"

# Readers on another host can fetch one file, but cannot enumerate this
# worktree's run directories. Rebuild under the shared writer lock so a
Expand Down Expand Up @@ -1396,12 +1398,7 @@ read_sentinel() {
[[ "$SENTINEL_EXIT" =~ ^[0-9]+$ ]] || die sentinel-unreadable "path=$run_dir/exit" "line=$line"
SENTINEL_AT="${line#* at=}"
SENTINEL_AT="${SENTINEL_AT%% *}"
case "$line" in
*" verdict=no-verdict cause=host") SENTINEL_VERDICT=no-verdict ;;
*" verdict=no-verdict") SENTINEL_VERDICT=no-verdict ;;
"guard-exit=0 "*) SENTINEL_VERDICT=pass ;;
*) SENTINEL_VERDICT=FAILING ;;
esac
SENTINEL_VERDICT="$(validation_verdict "$line")"
}

# --- Live: the run a start would refuse as run-live, read-only ---------------
Expand Down
12 changes: 12 additions & 0 deletions .agents/skills/orch/scripts/lib/validation-verdict.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# The runner's explicit marker records a timeout or unavailable host check.
# Foreground records use the same verdict rule without changing their raw exit.

validation_verdict() { # SENTINEL-LINE
case "$1" in
*" verdict=no-verdict cause=host") printf 'no-verdict\n' ;;
*" verdict=no-verdict") printf 'no-verdict\n' ;;
"guard-exit=0 "*) printf 'pass\n' ;;
*) printf 'FAILING\n' ;;
esac
}
1 change: 1 addition & 0 deletions .kendex-generated.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@
".agents/skills/orch/scripts/lib/tmux-server.sh",
".agents/skills/orch/scripts/lib/toml.sh",
".agents/skills/orch/scripts/lib/usage-reset.sh",
".agents/skills/orch/scripts/lib/validation-verdict.sh",
".agents/skills/orch/scripts/lib/verifying.sh",
".agents/skills/orch/scripts/lib/watch-handover.sh",
".agents/skills/orch/scripts/lib/watch-host-kinds.sh",
Expand Down
Loading
Loading