From 9db377943cbc054be67272d8ac9d2c10d0ec1bcd Mon Sep 17 00:00:00 2001 From: kjgbot Date: Tue, 1 Sep 2026 17:08:59 +0200 Subject: [PATCH] feat(preswarm): 3-lens pre-swarm check as a relayflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dogfoods gate 1: a real relayflow (workflows/preswarm-check.yaml) with three deterministic steps, invoked as `flows run workflows/preswarm-check.yaml`. Each step runs a lens (maintainability/history/structure) locally against the committed branch diff versus `main`; the kernel's implicit `exit_code == 0` gate on deterministic steps is the sole correctness authority. Purpose: catch the class of commit-message-truth issues (count off, "verbatim" not really verbatim, path wrong, fail-open-called- fail-closed) locally, before the post-push review-swarm burns a ~4-minute cycle surfacing them. WHAT SHIPS (against main, one commit). Numbers from `git diff main..HEAD --numstat`, pasted after staging and before writing this message: 2 0 .gitignore 117 0 ops/preswarm-check/README.md 259 0 ops/preswarm-check/lens-runner.sh 53 0 workflows/preswarm-check.yaml Behavioral summary - `workflows/preswarm-check.yaml` — 3 deterministic steps, one per lens. All three declare `dependsOn: []` so all three are runnable when the flow starts. The current kernel dispatches deterministic steps SERIALLY within a run, so wall-clock is ~sum of the three lens durations, not ~max. `timeoutMs: 930000` gives the runner (LENS_TIMEOUT=900s default) 30s headroom to classify NO_VERDICT before the step ceiling fires — in the COMMON path; see known limitations for the exceptions. - `ops/preswarm-check/lens-runner.sh`: 1. Detects `timeout` / `gtimeout` (macOS ships neither by default) and falls back to uncapped with a stderr warning. 2. Reads `git diff $BASE_REF..HEAD` (BASE_REF defaults to `main`) with stderr split to a separate temp file so git warnings do not contaminate the diff. 3. REFUSES with exit 3 when the diff modifies the pre-swarm-check itself — self-judging gate, RFC-0001 settled decision 6. PRESWARM_ALLOW_SELF_JUDGE=1 overrides with the understanding that the local outcome is not authoritative. 4. Empty diff → stderr warning + exit 0 (footgun documented). 5. Prompt passed on STDIN (not argv) so a large refactor does not exceed ARG_MAX (~256KB on macOS). 6. Classification: extracts the LAST anchored REVIEW_PASSED / REVIEW_FAILED line in the CLI output and dispatches on that single value. Never uses "any FAILED in the tail" — a review that quotes an earlier rejection while itself concluding PASSED resolves as PASSED (the DRIVE-LOG entry f59d9cd fix preserved). Fail-closed shape: LAST_VERDICT missing OR PASSED-with-non-zero- CLI-exit both degrade to NO_VERDICT (exit 1). - `ops/preswarm-check/README.md` — usage, environment, known limitations (self-judging refusal, `deterministic`-vs-`llm` vocabulary mismatch, serial-not-parallel dispatch, rulebook drift, empty-diff footgun, no classifier test). - `.gitignore` — ignore `.relayflowd/` and `.relayflowd-*/`. KNOWN LIMITATIONS (documented in the README) - **Self-judging refusal**: this shipping version REFUSES to run when the diff touches its own files; overridable with PRESWARM_ALLOW_SELF_JUDGE=1. The post-push swarm running from main IS the authoritative check for a self-touching PR. - **`type: deterministic` on LLM-shell-out steps**: RFC-0001 §2 reserves `deterministic` for pure scripts. The SDK's LlmStepSpec ships (`prompt` / `model` / `cli`) and preflight probes CLI existence + auth health, but `llm` steps embed a STATIC prompt at spec-write time — the pre-swarm-check needs to inject the CURRENT diff at run time. Until the SDK supports prompt templating in `llm` steps, a `deterministic` step that shells out to a runner that builds the prompt with the live diff is the only shape available. Named as a follow-up. - **Serial dispatch, not parallel**: the kernel currently runs the three declared-independent steps one at a time. Wall-clock is roughly the sum, ~10-15 min total. Parallel dispatch inside a single flow run is a kernel follow-up. - **Rulebook drift**: prompts here are similar to but not identical to `workflows/review-swarm.yaml` (the history-lens local prompt adds a "scaffolding PRs PASS" carve-out the post-push swarm YAML does not). Consolidating both into a single source file is the fix; not done here. - **Empty-diff PASSES with a stderr warning**. `--require-diff` flag is a follow-up. - **No classifier test**. The final-verdict-token discipline is load-bearing but not pinned by a test. A canned-output shell harness would pin it; deferred. - **`LENS_TIMEOUT` vs `timeoutMs` interaction**: two ceilings that must move together. When neither `timeout` nor `gtimeout` is present the runner runs uncapped and can hit the kernel's 930s step ceiling before classifying. Named in README. Co-Authored-By: Claude Opus 4.7 --- .gitignore | 2 + ops/preswarm-check/README.md | 117 ++++++++++++++ ops/preswarm-check/lens-runner.sh | 259 ++++++++++++++++++++++++++++++ workflows/preswarm-check.yaml | 53 ++++++ 4 files changed, 431 insertions(+) create mode 100644 ops/preswarm-check/README.md create mode 100755 ops/preswarm-check/lens-runner.sh create mode 100644 workflows/preswarm-check.yaml diff --git a/.gitignore b/.gitignore index 122d2e7eb..a4eca9004 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ dist/ .relayflows-toolchain/ .workflow-env .relayflow/ +.relayflowd/ +.relayflowd-*/ diff --git a/ops/preswarm-check/README.md b/ops/preswarm-check/README.md new file mode 100644 index 000000000..63a229f52 --- /dev/null +++ b/ops/preswarm-check/README.md @@ -0,0 +1,117 @@ +# Pre-swarm-check + +Run the 3-lens code review (maintainability / history / structure) on +the committed diff on this branch versus `main` **before** opening a PR, so +the post-push `review-swarm-loop.sh` does not have to spend ~4 minutes +per swarm cycle surfacing the same class of findings. + +## Why + +Every iteration of a PR that gets caught for a commit-message untruth +(count off, path wrong, "verbatim" not really verbatim), a rowid-vs-ULID +false claim, or a fail-open-called-fail-closed inversion burns: + +- ~4 min of swarm wall-clock across three lens processes +- one iteration of author time to write the fix +- one force-push + marker-scramble + kickstart cycle + +Running the identical lens prompts locally against the same diff catches +those before they hit main. The check IS a relayflow — three +deterministic steps invoking `sh ops/preswarm-check/lens-runner.sh +`, verified via the kernel's implicit `exit_code == 0` gate on deterministic steps (the runner exits 0 on REVIEW_PASSED, 1 on FAILED or NO_VERDICT). Same +kernel that runs `hn-monitor`, same PASSED/FAILED marker convention as +the post-push swarm. + +## Use + +From a repo checkout with your changes COMMITTED on a branch (staged- +but-uncommitted or unstaged changes are excluded — the check reviews +`git diff main..HEAD`, not the working tree): + +``` +flows run workflows/preswarm-check.yaml +``` + +Exit 0 means all three lenses PASSED — safe to push and open the PR. +Non-zero means at least one lens FAILED; the failing lens's full review +is in that step's stdout inside the run's journal +(`.relayflowd/runs/.sqlite3`). + +The three lenses are declared independent (`dependsOn: []`) so they +are all runnable when the flow starts, but the kernel's current +dispatch runs them SERIALLY (one step at a time), not concurrently. +Wall-clock is therefore roughly the sum of the three lens durations +(~10-15 min total, not ~4 min). Genuine parallel dispatch inside a +single flow run is a kernel follow-up. + +## Environment + +- `LENS_TIMEOUT` (seconds, default 900) — per-lens runner ceiling. + **Note**: `workflows/preswarm-check.yaml` also sets `timeoutMs: + 930000` (930s) as a HARD step ceiling the kernel enforces. Setting + `LENS_TIMEOUT` past ~900 has no effect unless the yaml's + `timeoutMs` is bumped in step. The 30s gap between them is + deliberate: the runner should always classify (emit `NO_VERDICT`) + before the kernel step kills the process. +- `BASE_REF` (default `main`) — the ref to diff against. `git diff + $BASE_REF..HEAD` is what the lens reviews. + +## What the lenses check + +Prompts of the same shape as `workflows/review-swarm.yaml`, adapted for +local pre-flight (the history-lens prompt here adds an explicit +"Scaffolding PRs PASS as long as they document deferrals" carve-out +the post-push swarm does not have). Rulebook drift between the two is +a known follow-up — consolidating both into one file both consumers +read is the right fix; that has not shipped yet. + +- **maintainability** (`claude -p`): unclear boundaries, implicit + contracts, missing failure handling, comments that assert what the + code does not do, tests that would not fail if the behavior broke. +- **history** (`codex exec`): repeats a DRIVE-LOG-recorded mistake, + introduces a new settled-RFC contradiction, or commit-message + untruths about the diff. +- **structure** (`opencode run`): boundaries, coupling, file size, + single-purpose; matches RFC-0001 (closed kernel vocabulary, + helpers over primitives, fail-closed, `completionReason` + discipline) and AGENTS.md. + +## Known limitations + +- **This is a LOCAL preflight, not a merge gate.** The actual merge + gate is the post-push `review-swarm` running from `main`'s copy of + the runner. Per RFC-0001 settled decision 6 ("gate definitions are + owned outside the mutating agent's write scope"), a branch that + modifies the runner or the flow spec is asking a potentially- + tampered gate to judge itself. `lens-runner.sh` **REFUSES** (exit + 3) when it detects such a diff. Override — with the understanding + that the local outcome is not authoritative — by setting + `PRESWARM_ALLOW_SELF_JUDGE=1`. In either case the post-push swarm + running from main is the real gate for a self-touching PR. +- **The lens steps are typed `deterministic` even though they invoke + LLM CLIs.** RFC-0001 reserves `deterministic` for pure scripts. + Migrating to `llm` steps would be the RFC-aligned shape, and the + SDK's `LlmStepSpec` already ships `prompt` / `model` / `cli` with + preflight CLI + auth-health probes. The blocker is not the SDK + — it is that `llm` steps embed a STATIC prompt at spec-write time, + and the pre-swarm-check needs to inject the CURRENT working diff + into the prompt at run time. Until the SDK supports prompt + templating (e.g. `{{diff_from(main)}}`), a `deterministic` step + that shells out to a runner that builds the prompt with the live + diff is the only shape available. Adding prompt templating to + `llm` steps unblocks the migration and is the correct follow-up. +- Requires `claude`, `codex`, `opencode` CLIs on PATH. If any is + missing the corresponding lens exits non-zero; the kernel's + implicit `exit_code == 0` gate then fails that step. +- The lens prompts are duplicated from `workflows/review-swarm.yaml`. + A rulebook drift between the two is a real risk; consolidating + them into a shared file both consumers read is a follow-up. +- No dedicated CLI runner test — the runner's exit code is the sole + correctness check. A shell harness that feeds canned outputs and + asserts the emitted marker + exit code (in particular pinning that + the classifier keys on the LAST anchored REVIEW_PASSED/FAILED line, + not any nearby mention) is a cheap follow-up worth adding. +- Empty diff versus `$BASE_REF` currently PASSES with a stderr + warning. Common footgun: wrong `BASE_REF` or forgotten commit + produces a spurious green. Consider an explicit `--require-diff` + flag as a follow-up. diff --git a/ops/preswarm-check/lens-runner.sh b/ops/preswarm-check/lens-runner.sh new file mode 100755 index 000000000..e8afbedc2 --- /dev/null +++ b/ops/preswarm-check/lens-runner.sh @@ -0,0 +1,259 @@ +#!/bin/sh +# Pre-swarm-check lens runner. Called from `workflows/preswarm-check.yaml` +# as a deterministic step for each of the three lenses (maintainability, +# history, structure). The prompts are the same shape the post-push +# review-swarm applies (see workflows/review-swarm.yaml). This file +# duplicates them today; consolidating them into one file both consumers +# read is called out in README as a known drift risk, not solved here. +# +# Usage: sh ops/preswarm-check/lens-runner.sh +# +# Reads the committed branch diff (`git diff $BASE_REF..HEAD`, NOT +# the working tree) and hands it to the +# lens CLI (`claude` / `codex` / `opencode`) — via stdin so the prompt +# is not bounded by ARG_MAX (~256KB on macOS). The lens is instructed +# to END its output with EXACTLY ONE of: +# REVIEW_PASSED — no blockers +# REVIEW_FAILED — at least one blocker +# +# Exit code IS the authority the flow spec keys on. Exits 0 when the +# CLI emitted REVIEW_PASSED; exits 1 on REVIEW_FAILED, on NO_VERDICT +# (CLI produced neither token), or on any CLI error. The kernel's +# implicit `exit_code == 0` gate for deterministic steps then fails +# the pre-swarm-check step. No `output_contains` gate is layered on +# top (that would be fail-open — the lens can quote arbitrary strings +# from the diff, including PASSED markers, so a substring match could +# not be trusted). +# +# The whole point of the pre-swarm-check: catch the swarm's classic +# findings (commit-message-vs-diff drift, count mismatches, missing +# FAIL-first mutations, evidence overreach) BEFORE the post-push swarm +# spends ~4 minutes surfacing them and burning a merge cycle. Every +# iteration this catches locally is one iteration the post-push loop +# does not have to run. + +# NOTE: `set -e` deliberately omitted. The CLI invocations below +# (`timeout ... claude/codex/opencode`) can exit non-zero for reasons +# the runner must SEE and turn into a NO_VERDICT / REVIEW_FAILED +# outcome (auth expired, rate limit, timeout = 124). With `set -e` +# the script would exit before reaching the classifier and the +# `PRESWARM_: ...` gate would fire on empty stderr, hiding the +# real failure mode. +set -u + +LENS=${1:-} +if [ -z "$LENS" ]; then + echo "lens-runner: missing lens name (maintainability|history|structure)" >&2 + exit 2 +fi + +# Longer timeout than the swarm's default because a local run does not +# compete for CLI capacity the way the swarm does mid-day. Still bounded +# so a hung CLI never wedges the pre-check. +LENS_TIMEOUT=${LENS_TIMEOUT:-900} +BASE_REF=${BASE_REF:-main} + +# `timeout` on macOS is not in the base install; coreutils installs +# `gtimeout`. Fall back cleanly so a stock Mac still runs this check. +# If neither is present we run without a wall-clock cap — noisier than +# ideal, but the alternative (refuse to run) is worse for a preflight. +if command -v timeout >/dev/null 2>&1; then + TIMEOUT_CMD="timeout $LENS_TIMEOUT" +elif command -v gtimeout >/dev/null 2>&1; then + TIMEOUT_CMD="gtimeout $LENS_TIMEOUT" +else + echo "lens-runner: neither timeout nor gtimeout on PATH; running lens uncapped" >&2 + TIMEOUT_CMD="" +fi + +DIFF_FILE=$(mktemp -t preswarm-diff.XXXXXX) +GIT_DIFF_STDERR=$(mktemp -t preswarm-diff-err.XXXXXX) +trap 'rm -f "$DIFF_FILE" "$GIT_DIFF_STDERR"' EXIT +if ! git diff "$BASE_REF"..HEAD > "$DIFF_FILE" 2> "$GIT_DIFF_STDERR"; then + echo "lens-runner: git diff $BASE_REF..HEAD failed; is $BASE_REF fetched?" >&2 + cat "$GIT_DIFF_STDERR" >&2 + exit 2 +fi +if [ -s "$GIT_DIFF_STDERR" ]; then + # Warnings from git-diff should not silently contaminate the diff + # the lens sees; surface them on stderr so the caller notices. + echo "lens-runner: git diff emitted stderr (surfaced, not embedded):" >&2 + cat "$GIT_DIFF_STDERR" >&2 +fi +# Self-judging-gate refusal. RFC-0001 settled decision 6: "Gate +# definitions are owned outside the mutating agent's write scope." +# A branch that modifies THIS runner or the flow spec that invokes +# it is asking a potentially-tampered gate to judge itself. Refuse +# by default; a developer who explicitly acknowledges the reduced +# integrity can override with PRESWARM_ALLOW_SELF_JUDGE=1. The +# actual merge gate remains the post-push review-swarm which runs +# from `main`'s copy of the runner — that IS the authoritative +# check for a diff that touches this tree. +if grep -qE '^diff --git a/(ops/preswarm-check/|workflows/preswarm-check\.yaml)' "$DIFF_FILE"; then + if [ "${PRESWARM_ALLOW_SELF_JUDGE:-0}" = "1" ]; then + echo "lens-runner: WARNING — self-judgment: this diff modifies the pre-swarm-check itself. PRESWARM_ALLOW_SELF_JUDGE=1 override in effect. The post-push review-swarm from main is the authoritative check." >&2 + else + echo "lens-runner: REFUSING to run — this diff modifies the pre-swarm-check itself (ops/preswarm-check/** or workflows/preswarm-check.yaml)." >&2 + echo "lens-runner: A branch-owned gate cannot judge its own modifications (RFC-0001 settled decision 6)." >&2 + echo "lens-runner: Set PRESWARM_ALLOW_SELF_JUDGE=1 to override with the understanding that the post-push review-swarm — running from main's copy — is the authoritative gate for this PR." >&2 + exit 3 + fi +fi +if [ ! -s "$DIFF_FILE" ]; then + # Empty diff is a truthful pass — there is nothing that could break. + # Common footgun: wrong BASE_REF or forgotten commit. Emit a WARNING + # to stderr so a caller notices, keep the marker shape identical to + # the non-empty path for legibility, and exit 0 so the kernel's + # implicit exit_code gate treats it as PASSED. + echo "lens-runner: WARNING — empty diff versus $BASE_REF. If you expected changes, check BASE_REF or that you committed." >&2 + echo "PRESWARM_${LENS}: REVIEW_PASSED" + exit 0 +fi + +case "$LENS" in + maintainability) + LENS_PROMPT='You are the MAINTAINABILITY lens on a code-review swarm. +Ask: could a stranger read this diff in six months and change it safely? +Name unclear boundaries, implicit contracts, missing failure handling, comments +that assert what the code does not do, and tests that would not fail if the +behavior broke.' + CLI=claude + ;; + history) + LENS_PROMPT='You are the HISTORY lens on a code-review swarm. +Run `git log --oneline -40` and read ops/DRIVE-LOG.md, ops/NEXT.md, and +ops/DIRECTIVES.md if present. Reject the diff ONLY on these three: + + 1. REPEATS a mistake DRIVE-LOG records — reintroduces a pattern a previous + commit deliberately removed. + 2. INTRODUCES a NEW contradiction with a settled RFC-0001 decision — the + diff adds a pattern the RFC explicitly rules out. + 3. The commit message TELLS UNTRUTHS about the diff — false claims about + tests, evidence, scope, or files touched. + +Scaffolding PRs (explicitly scoped, with deferrals documented in the commit +message or PR body) PASS this lens as long as they do not REGRESS +previously-fixed behavior and do not LIE. + +Do NOT reject on: + - Aspirational RFC decisions the diff does not yet fully realize. + - Pre-existing scaffolding the diff does not touch. + - Deferrals that name a follow-up (bundle digests, async drain + semantics, etc) instead of implementing them all at once. + - A drive-loop-generated file (like ops/NEXT.md) still referencing an + older gate — that is a follow-up brief-and-tick concern, not a + correctness violation of the diff being reviewed. + +Note those as concerns, not blockers. A scaffolding-first PR that lands +cleanly is more valuable than a monolithic first PR that lands never.' + CLI=codex + ;; + structure) + LENS_PROMPT='You are the STRUCTURE lens on a code-review swarm. +Ask: boundaries, coupling, file size and single purpose. Does the shape match +RFC-0001 (closed kernel vocabulary, helpers over primitives, fail-closed, +completionReason discipline) and AGENTS.md? Name anything that puts product +logic in the kernel, adds a primitive instead of a helper, or grows a file past +its purpose.' + CLI=opencode + ;; + *) + echo "lens-runner: unknown lens '$LENS' (expected maintainability|history|structure)" >&2 + exit 2 + ;; +esac + +# Read AGENTS.md and the RFC before reviewing so the lens has the same +# rulebook the post-push swarm does. `flow_key`, `spec_hash`, and other +# per-run context aren't relevant here — the lens is stateless. +FULL_PROMPT=$(cat <&1) || CLI_RC=$? + ;; + codex) + OUTPUT=$(printf '%s\n' "$FULL_PROMPT" | $TIMEOUT_CMD codex exec - 2>&1) || CLI_RC=$? + ;; + opencode) + OUTPUT=$(printf '%s\n' "$FULL_PROMPT" | $TIMEOUT_CMD opencode run 2>&1) || CLI_RC=$? + ;; + *) + # `$CLI` is only set from the LENS case above, so this is + # currently unreachable — but under `set -u` an unset `OUTPUT` + # below would explode with a cryptic error. Fail cleanly. + echo "lens-runner: internal error: unknown CLI '$CLI' for lens '$LENS'" >&2 + exit 2 + ;; +esac + +# Emit the full lens output so a caller can read the review verbatim, +# then a final PASSED/FAILED line for the verification gate. +printf '%s\n' "$OUTPUT" + +# Classification uses ONLY the LAST anchored verdict line — never +# "any FAILED anywhere in the tail". A review that quotes an earlier +# rejection ("prior reviews said REVIEW_FAILED for reason X") must +# still resolve to whatever verdict the reviewer commits to at the +# end. The two-step pipeline below extracts every line that is +# EXACTLY REVIEW_PASSED or EXACTLY REVIEW_FAILED (anchored by ^ and +# $), then keeps only the LAST one: +# +# LAST_VERDICT=$(grep -E '^REVIEW_(PASSED|FAILED)$' | tail -1) +# +# Fail-closed dispatch: +# - LAST_VERDICT == "REVIEW_FAILED" → exit 1 (FAILED) +# - LAST_VERDICT == "REVIEW_PASSED" AND CLI_RC == 0 → exit 0 (PASSED) +# - LAST_VERDICT == "REVIEW_PASSED" AND CLI_RC != 0 → exit 1 (NO_VERDICT — a CLI that emitted PASSED then errored is untrustworthy) +# - LAST_VERDICT missing (no anchored line at all) → exit 1 (NO_VERDICT) +LAST_VERDICT=$(printf '%s\n' "$OUTPUT" | grep -E '^REVIEW_(PASSED|FAILED)$' | tail -1) +case "$LAST_VERDICT" in + REVIEW_FAILED) + echo "PRESWARM_${LENS}: REVIEW_FAILED" + exit 1 + ;; + REVIEW_PASSED) + if [ "$CLI_RC" -eq 0 ]; then + echo "PRESWARM_${LENS}: REVIEW_PASSED" + exit 0 + fi + echo "PRESWARM_${LENS}: NO_VERDICT — final token was REVIEW_PASSED but CLI exit=${CLI_RC} (untrustworthy)" >&2 + exit 1 + ;; + *) + echo "PRESWARM_${LENS}: NO_VERDICT — no anchored REVIEW_PASSED or REVIEW_FAILED line in the CLI output (CLI exit=${CLI_RC})" >&2 + exit 1 + ;; +esac diff --git a/workflows/preswarm-check.yaml b/workflows/preswarm-check.yaml new file mode 100644 index 000000000..4437dfc7d --- /dev/null +++ b/workflows/preswarm-check.yaml @@ -0,0 +1,53 @@ +# Pre-swarm-check — run the 3-lens review on the COMMITTED branch diff +# BEFORE opening a PR, so the post-push review-swarm (workflows/review-swarm.yaml — see +# workflows/review-swarm.yaml) does not have to spend ~4 minutes +# surfacing the same class of findings and burning a merge cycle. +# +# Dogfoods gate 1 (deterministic flow runs on the kernel). +# +# Usage from a repo checkout: +# +# flows run workflows/preswarm-check.yaml +# +# Exit 0 = all three lenses PASSED, safe to push and open the PR. +# Non-zero = at least one lens FAILED. +# +# Gate: `exit_code == 0` is implicit for deterministic steps. Each +# lens's runner (ops/preswarm-check/lens-runner.sh) exits 0 on +# REVIEW_PASSED, 1 on REVIEW_FAILED, 1 on NO_VERDICT. NO output_contains +# gate is layered on top — the runner's exit code IS the authority. +# (An earlier version added `output_contains: "PRESWARM_: +# REVIEW_PASSED"`, which was fail-open: the lens can quote arbitrary +# strings from the diff in its review body, including the marker +# itself, so a substring match cannot be trusted as the sole gate.) +# +# The failing lens's full review lands in that step's stdout, which +# ends up in the run's per-run journal under +# .relayflowd/runs/.sqlite3 (or wherever --data-dir points). + +version: '0.1.0' +name: preswarm-check +description: > + Run the 3-lens code review (maintainability / history / structure) on + the committed branch diff versus main. Halts before push if any + lens rejects. + +steps: + - id: lens-maintainability + type: deterministic + dependsOn: [] + # 900s runner cap in lens-runner.sh + 30s headroom so the kernel + # never kills the step while the runner is emitting its NO_VERDICT + # classifier line on CLI timeout (exit=124). + timeoutMs: 930000 + command: "sh ops/preswarm-check/lens-runner.sh maintainability" + - id: lens-history + type: deterministic + dependsOn: [] + timeoutMs: 930000 + command: "sh ops/preswarm-check/lens-runner.sh history" + - id: lens-structure + type: deterministic + dependsOn: [] + timeoutMs: 930000 + command: "sh ops/preswarm-check/lens-runner.sh structure"