From 671fc60daaa6dd8e48070544b55f7281cc73e5fc Mon Sep 17 00:00:00 2001 From: Conan Scott Date: Wed, 4 Mar 2026 10:14:21 +0000 Subject: [PATCH] Add MACHINE.md --- MACHINE.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 MACHINE.md diff --git a/MACHINE.md b/MACHINE.md new file mode 100644 index 0000000..8abaf3a --- /dev/null +++ b/MACHINE.md @@ -0,0 +1,134 @@ +# MACHINE.md — Agent Context for ST Flow Test Harness + +This file is structured for consumption by AI agents. It defines the canonical test +patterns, expected behaviours, and how to operate the harness programmatically. + +## Repo Purpose + +Canonical test harness for ST Advanced Routing flows. Provides: +- Deterministic fixture files with known content and expected transforms +- Automated test runner (SFTP upload → route execution → destination verify) +- Declarative flow specs (YAML) for idempotent deploy +- Pre-flight environment snapshot tooling + +## Test Case Registry + +Each entry defines: fixture file, expected output filename, transform type, verification method. + +```json +[ + { + "id": "compress-txt", + "fixture": "fixtures/test.txt", + "fixture_sha256": "see fixtures/CHECKSUMS", + "expected_output_filename": "test.txt.zip", + "transform": "Compress", + "verify_method": "filename_suffix", + "verify_params": {"suffix": ".zip", "size_relation": "larger"}, + "notes": "ST Compress step appends .zip. Output size > input due to ZIP header overhead on small files." + }, + { + "id": "pgp-encrypt-md", + "fixture": "fixtures/test.md", + "fixture_sha256": "see fixtures/CHECKSUMS", + "expected_output_filename": "test.md.pgp", + "transform": "PgpEncryption", + "verify_method": "filename_suffix_and_magic_bytes", + "verify_params": { + "suffix": ".pgp", + "magic_bytes_hex": "C1", + "magic_bytes_offset": 0 + }, + "notes": "ST PgpEncryption appends .pgp. Binary output starts with 0xC1 (OpenPGP packet tag). Cert must have accessLevel=PUBLIC and account ownership." + }, + { + "id": "passthrough-csv", + "fixture": "fixtures/test.csv", + "fixture_sha256": "see fixtures/CHECKSUMS", + "expected_output_filename": "test.csv", + "transform": "None (pass-through)", + "verify_method": "exact_match", + "verify_params": {"filename_exact": true, "size_exact": true}, + "notes": "No step matches .csv. File passes through to SendToPartner unchanged." + }, + { + "id": "passthrough-pdf", + "fixture": "fixtures/test.pdf", + "fixture_sha256": "see fixtures/CHECKSUMS", + "expected_output_filename": "test.pdf", + "transform": "None (pass-through)", + "verify_method": "exact_match", + "verify_params": {"filename_exact": true, "size_exact": true}, + "notes": "No step matches .pdf. File passes through to SendToPartner unchanged." + }, + { + "id": "passthrough-jpg", + "fixture": "fixtures/test.jpg", + "fixture_sha256": "see fixtures/CHECKSUMS", + "expected_output_filename": "test.jpg", + "transform": "None (pass-through)", + "verify_method": "exact_match", + "verify_params": {"filename_exact": true, "size_exact": true}, + "notes": "No step matches .jpg. File passes through to SendToPartner unchanged." + } +] +``` + +## Script Interface + +### run_tests.py + +``` +python scripts/run_tests.py [--spec SPEC_YAML] [--env ENV_FILE] [--fixture FIXTURE] [--verbose] +``` + +- `--spec`: Path to flow spec YAML. Used to validate environment pre-flight. +- `--env`: Path to env file (default: `.env`). +- `--fixture`: Run only a single fixture (by id). Omit to run all. +- `--verbose`: Print step-by-step detail. + +Exit codes: `0` = all pass, `1` = one or more fail, `2` = environment/config error. + +Output format: JSON to stdout (machine-readable), human summary to stderr. + +### st_env_snapshot.py + +``` +python scripts/st_env_snapshot.py --host HOST --port PORT --user USER --pass PASS [--output json|yaml] +``` + +Returns a structured snapshot of the live ST environment: +- `accounts`: list of accounts with type and status +- `partner_sites`: list of partner sites with name, type, and partner account +- `certificates`: list of certs with name, type, usage, account, accessLevel +- `applications`: list of AR applications +- `subscriptions`: list of active subscriptions with folder and linked application + +Use this output to validate that all resources referenced in a flow spec exist before deploying. + +### st_deploy.py + +``` +python scripts/st_deploy.py --spec SPEC_YAML --host HOST --port PORT --user USER --pass PASS [--dry-run] +``` + +Idempotent deploy from spec YAML: +- Creates objects that don't exist +- Skips objects that exist with matching config +- Updates objects that exist with different config (route PUT, step rebuild) +- `--dry-run`: print planned actions without executing + +Exit codes: `0` = success, `1` = deploy error, `2` = validation error. + +## Known Constraints + +- **Route PUT drops step IDs**: When updating a route via PUT, omit all step `id` fields. Including them causes "Cannot attach a route step to another route" error. +- **conditionType is mandatory**: Every step must have explicit `conditionType: ALWAYS` or `EL`. Null causes NPE at runtime. +- **PGP cert must be PUBLIC**: Cert `accessLevel` must be `PUBLIC` and `account` must be a real account name. System-level or PRIVATE certs are invisible to the routing engine. +- **encryptKeyExpressionType**: Only `ALIAS` or `EXPRESSION_WILDCARD` are valid. `NAME` is rejected. +- **Routing latency**: Allow 15-30 seconds between upload and destination check. Use `ROUTING_TIMEOUT_SEC` env var. +- **Top-level Processed is insufficient**: Always verify at destination. A file with no matching step shows `Processed` at route level but was never transformed or delivered. + +## Spec Format Reference + +See `specs/schema.md` for full YAML spec format.