v0.4.3: cross-env bundle for regression — no direct peer protocol needed
Each Larry is independent. Bryan's question "how will Larry on Windows
talk to Larry on Linux for regression file transfer" answered: they don't.
File transfer is YOUR responsibility (scp / gh release / shared mount /
USB), but nc-regression now produces and consumes portable bundles that
make the split a one-command-on-each-side workflow.
Changes:
lib/nc-regression.sh
+ --phase env-a convenience for phases 1+2+3 (env-A side)
+ --phase env-b convenience for phases 4+5+6 (env-B side + diff)
+ --bundle-out PATH after env-A phases, tar inputs+outputs/env-a +
manifest.json + README.md + inbounds.txt
+ --bundle-in PATH at start, untar a bundle into $OUT; pulls scope
from the manifest so the env-B side just needs
--env-b and --route-test-cmd
MANUAL.md
+ New "Cross-environment Larry — how the boxes communicate" section
+ Bundle transport table (scp, gh release, NFS, USB, etc.)
+ Notes that the lesson loop uses the same local-capture / manual-
transport / central-merge model
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
a0502e2ec6
commit
b141d54847
60
MANUAL.md
60
MANUAL.md
@ -398,6 +398,66 @@ Output: markdown report with cluster overview, per-thread protocol-block diff, p
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Cross-environment Larry — how the boxes communicate
|
||||||
|
|
||||||
|
**They don't, directly.** Each Larry on each box is independent. For regression
|
||||||
|
testing across two firewalled environments, the workflow is:
|
||||||
|
|
||||||
|
```
|
||||||
|
env-A (Windows) env-B (Linux)
|
||||||
|
nc-regression --phase env-a → nc-regression --phase env-b
|
||||||
|
--bundle-out /tmp/reg.tar.gz --bundle-in /tmp/reg.tar.gz
|
||||||
|
│ │
|
||||||
|
└────── you move the bundle ────────┘
|
||||||
|
(scp, gh release, USB,
|
||||||
|
shared mount, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--bundle-out` flag (after env-A phases 1-3) produces a tarball with:
|
||||||
|
- `inputs/*.msgs` — sampled messages from env-A smatdbs
|
||||||
|
- `outputs/env-a/*/*.out` — env-A route_test outputs
|
||||||
|
- `manifest.json` — env-A metadata + hints
|
||||||
|
- `inbounds.txt` — the threads tested
|
||||||
|
- `README.md` — instructions for the env-B side
|
||||||
|
|
||||||
|
Move the bundle however you can (see below). Then on env-B:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nc-regression.sh \
|
||||||
|
--bundle-in /path/to/reg.tar.gz \
|
||||||
|
--out /tmp/reg \
|
||||||
|
--env-b $HCIROOT --site-b $HCISITE \
|
||||||
|
--route-test-cmd '<env-b route_test command>' \
|
||||||
|
--phase env-b
|
||||||
|
```
|
||||||
|
|
||||||
|
That runs phases 4-6 (route_test on env-B with same inputs, diff each pair,
|
||||||
|
master summary).
|
||||||
|
|
||||||
|
### Bundle transport options (pick whichever your network allows)
|
||||||
|
|
||||||
|
| how | when |
|
||||||
|
|---|---|
|
||||||
|
| `scp` between the boxes | both boxes mutually SSH-reachable |
|
||||||
|
| `scp` to your laptop, `scp` to env-B | you can SSH to each separately |
|
||||||
|
| Private GitHub release / gist | both boxes can reach github.com but not each other |
|
||||||
|
| Shared NFS / SMB mount | the boxes share a filesystem |
|
||||||
|
| Box / SharePoint / S3 | enterprise common-storage |
|
||||||
|
| USB stick / portable drive | nothing else works |
|
||||||
|
| Tarball as email attachment | small bundles, both boxes have email |
|
||||||
|
|
||||||
|
The bundle is plain `tar.gz` — nothing Cloverleaf-specific. Inspect it with
|
||||||
|
`tar -tzf reg.tar.gz` to see what's inside before moving it.
|
||||||
|
|
||||||
|
### Lessons / refinements use the same pattern
|
||||||
|
|
||||||
|
Larry on a client captures lessons locally (`/lesson`, lesson_record tool).
|
||||||
|
You export the lesson bundle with `lib/lessons.sh export` and paste it back
|
||||||
|
to home-Larry (the dev-machine session you have with me). Same model:
|
||||||
|
local capture, manual transport, central merge. No direct peer protocol.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Regression testing — end to end (`lib/nc-regression.sh`)
|
## Regression testing — end to end (`lib/nc-regression.sh`)
|
||||||
|
|
||||||
Full Example 6 orchestrator. Six phases: discover → sample → route-test A → route-test B → diff → summary.
|
Full Example 6 orchestrator. Six phases: discover → sample → route-test A → route-test B → diff → summary.
|
||||||
|
|||||||
2
larry.sh
2
larry.sh
@ -32,7 +32,7 @@ set -o pipefail
|
|||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# Config
|
# Config
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
LARRY_VERSION="0.4.2"
|
LARRY_VERSION="0.4.3"
|
||||||
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
|
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
|
||||||
LARRY_UPDATE_URL="${LARRY_UPDATE_URL:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main/larry.sh}"
|
LARRY_UPDATE_URL="${LARRY_UPDATE_URL:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main/larry.sh}"
|
||||||
LARRY_AGENTS_URL="${LARRY_AGENTS_URL:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main/agents}"
|
LARRY_AGENTS_URL="${LARRY_AGENTS_URL:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main/agents}"
|
||||||
|
|||||||
@ -70,6 +70,8 @@ DRY_RUN=0
|
|||||||
INBOUND_MODE="all"
|
INBOUND_MODE="all"
|
||||||
ENV_B_HOST=""
|
ENV_B_HOST=""
|
||||||
ENV_B_USER=""
|
ENV_B_USER=""
|
||||||
|
BUNDLE_OUT="" # after env-A phases, tar up the artifacts here
|
||||||
|
BUNDLE_IN="" # at start, untar a bundle here as the env-A artifacts
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -88,6 +90,8 @@ while [ $# -gt 0 ]; do
|
|||||||
--inbound-mode) shift; INBOUND_MODE="$1" ;;
|
--inbound-mode) shift; INBOUND_MODE="$1" ;;
|
||||||
--env-b-host) shift; ENV_B_HOST="$1" ;;
|
--env-b-host) shift; ENV_B_HOST="$1" ;;
|
||||||
--env-b-user) shift; ENV_B_USER="$1" ;;
|
--env-b-user) shift; ENV_B_USER="$1" ;;
|
||||||
|
--bundle-out) shift; BUNDLE_OUT="$1" ;;
|
||||||
|
--bundle-in) shift; BUNDLE_IN="$1" ;;
|
||||||
-h|--help) sed -n '2,55p' "$NC_SELF"; exit 0 ;;
|
-h|--help) sed -n '2,55p' "$NC_SELF"; exit 0 ;;
|
||||||
-*) die "unknown flag: $1" ;;
|
-*) die "unknown flag: $1" ;;
|
||||||
*) die "extra arg: $1" ;;
|
*) die "extra arg: $1" ;;
|
||||||
@ -95,16 +99,35 @@ while [ $# -gt 0 ]; do
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
[ -n "$SCOPE" ] || die "missing --scope (thread:NAME | threads:N1,N2 | site | server)"
|
|
||||||
[ -n "$ENV_A" ] || die "missing --env-a HCIROOT_A"
|
|
||||||
[ -n "$ENV_B" ] || die "missing --env-b HCIROOT_B"
|
|
||||||
[ -n "$OUT" ] || die "missing --out DIR"
|
[ -n "$OUT" ] || die "missing --out DIR"
|
||||||
[ -d "$ENV_A" ] || die "env-a is not a directory: $ENV_A"
|
# When --bundle-in is given, we don't need scope/env-a/etc. — the bundle has them.
|
||||||
case "$PHASE" in 1|2|3|4|5|6|all) ;; *) die "bad --phase" ;; esac
|
if [ -z "$BUNDLE_IN" ]; then
|
||||||
|
[ -n "$SCOPE" ] || die "missing --scope (thread:NAME | threads:N1,N2 | site | server)"
|
||||||
|
[ -n "$ENV_A" ] || die "missing --env-a HCIROOT_A"
|
||||||
|
[ -n "$ENV_B" ] || die "missing --env-b HCIROOT_B"
|
||||||
|
[ -d "$ENV_A" ] || die "env-a is not a directory: $ENV_A"
|
||||||
|
fi
|
||||||
|
case "$PHASE" in 1|2|3|4|5|6|all|env-a|env-b) ;; *) die "bad --phase (use 1|2|3|4|5|6|all|env-a|env-b)" ;; esac
|
||||||
[ "$DRY_RUN" = "1" ] || [ -n "$ROUTE_TEST_CMD" ] || say "WARNING: --route-test-cmd is unset; phases 3 and 4 will be skipped (you can run them manually using the generated input files)"
|
[ "$DRY_RUN" = "1" ] || [ -n "$ROUTE_TEST_CMD" ] || say "WARNING: --route-test-cmd is unset; phases 3 and 4 will be skipped (you can run them manually using the generated input files)"
|
||||||
|
|
||||||
mkdir -p "$OUT" "$OUT/inputs" "$OUT/outputs/env-a" "$OUT/outputs/env-b" "$OUT/diff" 2>/dev/null
|
mkdir -p "$OUT" "$OUT/inputs" "$OUT/outputs/env-a" "$OUT/outputs/env-b" "$OUT/diff" 2>/dev/null
|
||||||
|
|
||||||
|
# If --bundle-in given, untar the bundle into $OUT first. Manifest tells us
|
||||||
|
# what env-A was and (optionally) what route_test command to use.
|
||||||
|
if [ -n "$BUNDLE_IN" ]; then
|
||||||
|
[ -f "$BUNDLE_IN" ] || die "bundle-in file not found: $BUNDLE_IN"
|
||||||
|
say "unpacking bundle $BUNDLE_IN into $OUT/"
|
||||||
|
tar -xzf "$BUNDLE_IN" -C "$OUT" 2>&1 | tail -5
|
||||||
|
if [ -f "$OUT/manifest.json" ]; then
|
||||||
|
say "manifest from env-A:"
|
||||||
|
cat "$OUT/manifest.json" >&2
|
||||||
|
# Pull scope and route-test-cmd hints if not overridden
|
||||||
|
if [ -z "$SCOPE" ] && command -v jq >/dev/null 2>&1; then
|
||||||
|
SCOPE=$(jq -r '.scope // ""' "$OUT/manifest.json")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
# Phase 1: discover inbound threads in scope
|
# Phase 1: discover inbound threads in scope
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
@ -328,5 +351,50 @@ case "$PHASE" in
|
|||||||
5) phase_5 ;;
|
5) phase_5 ;;
|
||||||
6) phase_6 ;;
|
6) phase_6 ;;
|
||||||
all) phase_1 && phase_2 && phase_3 && phase_4 && phase_5 && phase_6 ;;
|
all) phase_1 && phase_2 && phase_3 && phase_4 && phase_5 && phase_6 ;;
|
||||||
|
env-a) phase_1 && phase_2 && phase_3 ;; # everything that uses env-A
|
||||||
|
env-b) phase_4 && phase_5 && phase_6 ;; # everything that uses env-B + diff
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Optional: produce a portable bundle of the env-A artifacts (inputs + a-outputs)
|
||||||
|
# so the user can move them to the env-B box manually.
|
||||||
|
if [ -n "$BUNDLE_OUT" ]; then
|
||||||
|
say "producing bundle: $BUNDLE_OUT"
|
||||||
|
{
|
||||||
|
printf '{'
|
||||||
|
printf '"generated":"%s",' "$(date -Iseconds 2>/dev/null || date)"
|
||||||
|
printf '"host":"%s",' "$(hostname 2>/dev/null || echo unknown)"
|
||||||
|
printf '"env_a":"%s",' "$ENV_A"
|
||||||
|
printf '"site_a":"%s",' "$SITE_A"
|
||||||
|
printf '"env_b_expected":"%s",' "$ENV_B"
|
||||||
|
printf '"site_b_expected":"%s",' "$SITE_B"
|
||||||
|
printf '"scope":"%s",' "$SCOPE"
|
||||||
|
printf '"count":%s,' "$COUNT"
|
||||||
|
printf '"ignore":"%s",' "$IGNORE"
|
||||||
|
printf '"route_test_cmd_hint":"%s"' "$ROUTE_TEST_CMD"
|
||||||
|
printf '}\n'
|
||||||
|
} > "$OUT/manifest.json"
|
||||||
|
cat > "$OUT/README.md" <<EOF
|
||||||
|
# Regression bundle — env-A artifacts
|
||||||
|
|
||||||
|
Take this bundle to the env-B box and run:
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
nc-regression.sh --bundle-in $(basename "$BUNDLE_OUT") --out $OUT \\
|
||||||
|
--env-b /path/to/env-b/integrator --site-b <site> \\
|
||||||
|
--route-test-cmd '<env-b route_test command>' \\
|
||||||
|
--phase env-b
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
The bundle contains:
|
||||||
|
- inputs/ — sampled messages from env-A (one .msgs per inbound)
|
||||||
|
- outputs/env-a/ — route_test outputs from env-A
|
||||||
|
- manifest.json — env-A metadata
|
||||||
|
- inbounds.txt — the threads tested
|
||||||
|
|
||||||
|
env-B side will produce outputs/env-b/ and the diff/ tree.
|
||||||
|
EOF
|
||||||
|
tar -czf "$BUNDLE_OUT" -C "$OUT" inputs outputs/env-a inbounds.txt manifest.json README.md 2>/dev/null
|
||||||
|
say "bundle ready: $BUNDLE_OUT ($(du -h "$BUNDLE_OUT" | awk '{print $1}'))"
|
||||||
|
fi
|
||||||
|
|
||||||
say "regression run done. Output root: $OUT"
|
say "regression run done. Output root: $OUT"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user