From ac6944c6ec0782407d6c4cf8e675557855226202 Mon Sep 17 00:00:00 2001 From: RomirJ Date: Wed, 10 Jun 2026 16:13:46 -0700 Subject: [PATCH] fix: rename-completeness sweep + correct install hints + broken doc commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes a cluster of v0.12.0 rename casualties and onboarding breakage found in the full-codebase audit (reflex_context/02_research/2026-06-10-tether-oss- improvement-audit.md, Part 1 #2 + #7): Install hints (supply-chain): three hints still told users to `pip install 'tether[...]'`, but the bare `tether` name is foreign-owned on PyPI — the dist is `fastcrest-tether`. Fixed cli.py:39 (tui), :3027 (serve,gpu), :3617 (serve extra). Broken generated/doc commands: `validate` is a Typer group (`tether validate export `); the bare `tether validate ` form was removed (now `validate-legacy`, hidden). Every adopter's generated CI and every verification report reproducer emitted the dead form. Fixed ci_template.py:53, verification_report.py:66,177. README SDK examples imported `ReflexClient` (nonexistent → ImportError) in both Python snippets — the only SDK examples a new integrator copies. Fixed to `TetherClient`. Grafana dashboards queried `reflex_*` metrics while the code emits `tether_*` (observability/prometheus.py) — every panel was silently empty. Renamed all metric queries + cosmetic titles/uids/tags in both dashboards; JSON revalidated. Docs referenced `reflex_config.json`; the exporter writes `tether_config.json` (verification_report.py:124, _pytorch_backend.py). Fixed docs/getting_started.md, docs/verification.md, reference/NOTES.md. (CHANGELOG historical entries left as shipped-state record.) License accuracy: pyproject classifier claimed "OSI Approved :: Apache Software License" on a BUSL-1.1 package (also conflicts with the PEP-639 SPDX `license` field) — removed. LICENSE "Licensed Work: Reflex" → "Tether (formerly Reflex)" so the legal scope names the current work while preserving 0.5.0–0.11.x continuity. Co-Authored-By: Claude Opus 4.7 (1M context) --- LICENSE | 4 ++-- README.md | 8 ++++---- dashboards/grafana_template.json | 30 +++++++++++++++--------------- dashboards/tether_fleet.json | 26 +++++++++++++------------- docs/getting_started.md | 4 ++-- docs/verification.md | 2 +- pyproject.toml | 5 ++++- reference/NOTES.md | 2 +- src/tether/ci_template.py | 2 +- src/tether/cli.py | 6 +++--- src/tether/verification_report.py | 4 ++-- 11 files changed, 48 insertions(+), 45 deletions(-) diff --git a/LICENSE b/LICENSE index ad297e6a..3b71963a 100644 --- a/LICENSE +++ b/LICENSE @@ -4,8 +4,8 @@ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved. Parameters Licensor: FastCrest -Licensed Work: Reflex Version 0.5.0 or later. The Licensed Work is (c) 2026 - FastCrest +Licensed Work: Tether (formerly Reflex) Version 0.5.0 or later. The + Licensed Work is (c) 2026 FastCrest Additional Use Grant: You may make production use of the Licensed Work, provided Your use does not include offering the Licensed Work to third parties on a hosted or embedded basis in order to compete with diff --git a/README.md b/README.md index 6ca41094..734fdbd5 100644 --- a/README.md +++ b/README.md @@ -185,9 +185,9 @@ when you're ready for per-robot normalization + ActionGuard clamping. Then from your code: ```python -from tether.client import ReflexClient +from tether.client import TetherClient -with ReflexClient("http://localhost:8000") as client: +with TetherClient("http://localhost:8000") as client: with client.episode() as ep: # auto episode_id, RTC reset result = ep.act(image=numpy_frame, state=[0.1, 0.2, ...]) print(result["actions"]) # list of action chunks @@ -240,9 +240,9 @@ The Python client sets `X-Tether-Key` when `api_key` is provided: ```python import os -from tether.client import ReflexClient +from tether.client import TetherClient -with ReflexClient("http://localhost:8000", api_key=os.environ["TETHER_API_KEY"]) as client: +with TetherClient("http://localhost:8000", api_key=os.environ["TETHER_API_KEY"]) as client: result = client.act( image=numpy_frame, state=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6], diff --git a/dashboards/grafana_template.json b/dashboards/grafana_template.json index 76ce5e22..5c22a8fe 100644 --- a/dashboards/grafana_template.json +++ b/dashboards/grafana_template.json @@ -2,7 +2,7 @@ "annotations": { "list": [] }, - "description": "Reflex VLA serve — out-of-the-box dashboard. 5 panels: latency p99, cache hit rate, in-flight, safety/SLO violations, server up. Tested against Grafana 10.4.0 (schemaVersion 39). Datasource ${DS_PROMETHEUS} resolved at import time. See features/01_serve/subfeatures/_ecosystem/prometheus-grafana.md.", + "description": "Tether VLA serve — out-of-the-box dashboard. 5 panels: latency p99, cache hit rate, in-flight, safety/SLO violations, server up. Tested against Grafana 10.4.0 (schemaVersion 39). Datasource ${DS_PROMETHEUS} resolved at import time. See features/01_serve/subfeatures/_ecosystem/prometheus-grafana.md.", "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 1, @@ -48,7 +48,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "histogram_quantile(0.99, sum(rate(reflex_act_latency_seconds_bucket[5m])) by (embodiment, le))", + "expr": "histogram_quantile(0.99, sum(rate(tether_act_latency_seconds_bucket[5m])) by (embodiment, le))", "legendFormat": "p99 — {{embodiment}}", "range": true, "refId": "A" @@ -99,7 +99,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "sum(rate(reflex_cache_hit_total[5m])) / (sum(rate(reflex_cache_hit_total[5m])) + sum(rate(reflex_cache_miss_total[5m])))", + "expr": "sum(rate(tether_cache_hit_total[5m])) / (sum(rate(tether_cache_hit_total[5m])) + sum(rate(tether_cache_miss_total[5m])))", "legendFormat": "Hit rate", "refId": "A" } @@ -146,8 +146,8 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "reflex_server_up", - "legendFormat": "reflex serve", + "expr": "tether_server_up", + "legendFormat": "tether serve", "refId": "A" } ], @@ -181,7 +181,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(reflex_safety_violations_total[5m])) by (violation_kind)", + "expr": "sum(rate(tether_safety_violations_total[5m])) by (violation_kind)", "legendFormat": "safety: {{violation_kind}}", "refId": "A" }, @@ -190,7 +190,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(reflex_slo_violations_total[5m])) by (slo_kind)", + "expr": "sum(rate(tether_slo_violations_total[5m])) by (slo_kind)", "legendFormat": "SLO: {{slo_kind}}", "refId": "B" } @@ -235,7 +235,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(reflex_in_flight_requests) by (embodiment)", + "expr": "sum(tether_in_flight_requests) by (embodiment)", "legendFormat": "{{embodiment}}", "refId": "A" } @@ -247,7 +247,7 @@ "refresh": "10s", "schemaVersion": 39, "style": "dark", - "tags": ["reflex-vla", "serve"], + "tags": ["tether-vla", "serve"], "templating": { "list": [ { @@ -260,7 +260,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "definition": "label_values(reflex_act_latency_seconds_count, embodiment)", + "definition": "label_values(tether_act_latency_seconds_count, embodiment)", "hide": 0, "includeAll": true, "multi": true, @@ -268,7 +268,7 @@ "options": [], "query": { "qryType": 1, - "query": "label_values(reflex_act_latency_seconds_count, embodiment)", + "query": "label_values(tether_act_latency_seconds_count, embodiment)", "refId": "PrometheusVariableQueryEditor-VariableQuery" }, "refresh": 1, @@ -285,7 +285,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "definition": "label_values(reflex_act_latency_seconds_count, model_id)", + "definition": "label_values(tether_act_latency_seconds_count, model_id)", "hide": 0, "includeAll": true, "multi": true, @@ -293,7 +293,7 @@ "options": [], "query": { "qryType": 1, - "query": "label_values(reflex_act_latency_seconds_count, model_id)", + "query": "label_values(tether_act_latency_seconds_count, model_id)", "refId": "PrometheusVariableQueryEditor-VariableQuery" }, "refresh": 1, @@ -305,8 +305,8 @@ "time": { "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", - "title": "Reflex VLA Serve", - "uid": "reflex-vla-serve", + "title": "Tether VLA Serve", + "uid": "tether-vla-serve", "version": 1, "weekStart": "" } diff --git a/dashboards/tether_fleet.json b/dashboards/tether_fleet.json index 230de091..f8457b83 100644 --- a/dashboards/tether_fleet.json +++ b/dashboards/tether_fleet.json @@ -1,6 +1,6 @@ { "annotations": { "list": [] }, - "description": "Tether fleet dashboard — per-robot breakdown. Requires `tether serve --robot-id ` on each process so the `reflex_robot_info` gauge is populated. Panels join hot metrics against robot_info via `instance`. Tested against Grafana 10.4.0 (schemaVersion 39). See features/01_serve/subfeatures/_ecosystem/fleet-telemetry/fleet-telemetry.md.", + "description": "Tether fleet dashboard — per-robot breakdown. Requires `tether serve --robot-id ` on each process so the `tether_robot_info` gauge is populated. Panels join hot metrics against robot_info via `instance`. Tested against Grafana 10.4.0 (schemaVersion 39). See features/01_serve/subfeatures/_ecosystem/fleet-telemetry/fleet-telemetry.md.", "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 1, @@ -11,7 +11,7 @@ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "title": "Active robots", - "description": "Count of robot processes reporting `reflex_robot_info`. One series per robot_id; drops to 0 when a robot goes offline.", + "description": "Count of robot processes reporting `tether_robot_info`. One series per robot_id; drops to 0 when a robot goes offline.", "gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 }, "id": 1, "type": "stat", @@ -30,7 +30,7 @@ "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "count(reflex_robot_info{robot_id=~\"$robot\"})", + "expr": "count(tether_robot_info{robot_id=~\"$robot\"})", "legendFormat": "robots", "refId": "A" } @@ -58,7 +58,7 @@ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "histogram_quantile(0.99, sum by (le, instance) (rate(reflex_act_latency_seconds_bucket[5m]))) * on (instance) group_left(robot_id) reflex_robot_info{robot_id=~\"$robot\"}", + "expr": "histogram_quantile(0.99, sum by (le, instance) (rate(tether_act_latency_seconds_bucket[5m]))) * on (instance) group_left(robot_id) tether_robot_info{robot_id=~\"$robot\"}", "legendFormat": "{{robot_id}}", "refId": "A" } @@ -81,7 +81,7 @@ "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum by (instance) (rate(reflex_act_latency_seconds_count[1m])) * on (instance) group_left(robot_id) reflex_robot_info{robot_id=~\"$robot\"}", + "expr": "sum by (instance) (rate(tether_act_latency_seconds_count[1m])) * on (instance) group_left(robot_id) tether_robot_info{robot_id=~\"$robot\"}", "legendFormat": "{{robot_id}}", "refId": "A" } @@ -104,7 +104,7 @@ "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum by (instance, violation_kind) (increase(reflex_safety_violations_total[5m])) * on (instance) group_left(robot_id) reflex_robot_info{robot_id=~\"$robot\"}", + "expr": "sum by (instance, violation_kind) (increase(tether_safety_violations_total[5m])) * on (instance) group_left(robot_id) tether_robot_info{robot_id=~\"$robot\"}", "legendFormat": "{{robot_id}} / {{violation_kind}}", "refId": "A" } @@ -126,7 +126,7 @@ "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum by (instance) (reflex_in_flight_requests) * on (instance) group_left(robot_id) reflex_robot_info{robot_id=~\"$robot\"}", + "expr": "sum by (instance) (tether_in_flight_requests) * on (instance) group_left(robot_id) tether_robot_info{robot_id=~\"$robot\"}", "legendFormat": "{{robot_id}}", "refId": "A" } @@ -148,7 +148,7 @@ "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum by (instance, slo_kind) (increase(reflex_slo_violations_total[5m])) * on (instance) group_left(robot_id) reflex_robot_info{robot_id=~\"$robot\"}", + "expr": "sum by (instance, slo_kind) (increase(tether_slo_violations_total[5m])) * on (instance) group_left(robot_id) tether_robot_info{robot_id=~\"$robot\"}", "legendFormat": "{{robot_id}} / {{slo_kind}}", "refId": "A" } @@ -157,20 +157,20 @@ ], "refresh": "10s", "schemaVersion": 39, - "tags": ["reflex", "fleet", "vla"], + "tags": ["tether", "fleet", "vla"], "templating": { "list": [ { "current": { "selected": true, "text": "All", "value": "$__all" }, "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "definition": "label_values(reflex_robot_info, robot_id)", + "definition": "label_values(tether_robot_info, robot_id)", "hide": 0, "includeAll": true, "label": "Robot", "multi": true, "name": "robot", "options": [], - "query": { "query": "label_values(reflex_robot_info, robot_id)", "refId": "StandardVariableQuery" }, + "query": { "query": "label_values(tether_robot_info, robot_id)", "refId": "StandardVariableQuery" }, "refresh": 2, "regex": "", "skipUrlSync": false, @@ -182,8 +182,8 @@ "time": { "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", - "title": "Reflex Fleet", - "uid": "reflex-fleet", + "title": "Tether Fleet", + "uid": "tether-fleet", "version": 1, "weekStart": "", "__inputs": [ diff --git a/docs/getting_started.md b/docs/getting_started.md index 40f33264..538dd891 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -48,7 +48,7 @@ tether export nvidia/GR00T-N1.6-3B --target orin --output ./gr00t Each command: 1. Downloads the checkpoint from HuggingFace (cached after first run) 2. Runs the model-specific exporter (auto-dispatches based on key prefix) -3. Writes ONNX + reflex_config.json into `--output` +3. Writes ONNX + tether_config.json into `--output` 4. Validates the ONNX numerically against the PyTorch reference (max_diff < 1e-5) 5. If trtexec is available, builds a TensorRT engine @@ -60,7 +60,7 @@ After export your output directory looks like: ./pi0/ ├── expert_stack.onnx # the graph (1.25MB) ├── expert_stack.onnx.data # the weights (~1.3GB for pi0) -├── reflex_config.json # model meta — used by serve +├── tether_config.json # model meta — used by serve └── expert_stack.trt # TRT engine (only if trtexec was available) ``` diff --git a/docs/verification.md b/docs/verification.md index cb338c3e..1b1b4527 100644 --- a/docs/verification.md +++ b/docs/verification.md @@ -57,7 +57,7 @@ Total: **3 files, 247.5MB** | File | Size | SHA256 | |---|---|---| | `model.onnx` | 245.3MB | `a1b2c3d4...` | -| `reflex_config.json` | 1.2KB | `e5f6a7b8...` | +| `tether_config.json` | 1.2KB | `e5f6a7b8...` | | `tokenizer.json` | 957KB | `f9a0b1c2...` | ``` diff --git a/pyproject.toml b/pyproject.toml index 1f514642..0e8cd1c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,10 @@ classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Topic :: Scientific/Engineering :: Artificial Intelligence", - "License :: OSI Approved :: Apache Software License", + # License is declared via the SPDX `license = "BUSL-1.1"` expression above + # (PEP 639). BUSL-1.1 is not OSI-approved, so there is no License :: + # classifier — and emitting an Apache one here would both misrepresent the + # license and conflict with the SPDX field on modern build backends. "Programming Language :: Python :: 3", ] diff --git a/reference/NOTES.md b/reference/NOTES.md index 4098e599..49da935f 100644 --- a/reference/NOTES.md +++ b/reference/NOTES.md @@ -206,7 +206,7 @@ Our buffer is great, but we lack: Steps: 1. Read `/reference/lerobot/src/lerobot/policies/xvla/action_hub.py` fully. 2. Extract action space definitions (min/max per joint, continuous vs. discrete). - 3. Add action denormalization to `predict()` post-inference. Needs a config field in `reflex_config.json` (action_space definition). + 3. Add action denormalization to `predict()` post-inference. Needs a config field in `tether_config.json` (action_space definition). 4. For RTC: add soft constraint checking in a new `ActionRTC` class (similar to `ActionGuard`). Return violations as telemetry, let the robot decide to replan. ### Priority for our roadmap diff --git a/src/tether/ci_template.py b/src/tether/ci_template.py index 4de96ba8..9799e229 100644 --- a/src/tether/ci_template.py +++ b/src/tether/ci_template.py @@ -50,7 +50,7 @@ - name: Validate round-trip parity run: | - tether validate ./sv_export --threshold 1e-4 --num-cases 3 --output-json > validate_result.json + tether validate export ./sv_export --threshold 1e-4 --num-cases 3 --output-json > validate_result.json - name: Upload validation report if: always() diff --git a/src/tether/cli.py b/src/tether/cli.py index dca60bd4..52deb44f 100644 --- a/src/tether/cli.py +++ b/src/tether/cli.py @@ -36,7 +36,7 @@ [bold cyan]Most-used:[/bold cyan] [green]tether chat[/green] start the natural-language assistant - [green]tether chat --tui[/green] ↳ full-screen TUI (needs [dim]pip install 'tether\\[tui]'[/dim]) + [green]tether chat --tui[/green] ↳ full-screen TUI (needs [dim]pip install 'fastcrest-tether\\[tui]'[/dim]) [green]tether go --model X[/green] one-command deploy: probe → pull → export → serve [green]tether doctor[/green] diagnose install + GPU issues [green]tether models list[/green] browse the curated model registry @@ -3024,7 +3024,7 @@ def _find_lib(libname: str) -> str | None: # in the doctor table. libs = [ ("libnvinfer.so.10", "TensorRT runtime", - r"pip install 'tether\[serve,gpu]' (brings tensorrt>=10)"), + r"pip install 'fastcrest-tether\[serve,gpu]' (brings tensorrt>=10)"), ("libcublas.so.12", "CUDA cuBLAS", r"pip install nvidia-cublas-cu12 (auto-included in \[serve,gpu])"), ("libcudnn.so.9", "CUDA cuDNN", @@ -3614,7 +3614,7 @@ def _arch_from_name(name: str) -> str: add( "fastapi + uvicorn", False, - f"not installed — run `pip install 'tether\\[{extra}]'` for the server", + f"not installed — run `pip install 'fastcrest-tether\\[{extra}]'` for the server", ) # safetensors diff --git a/src/tether/verification_report.py b/src/tether/verification_report.py index 3354baca..546e7bb4 100644 --- a/src/tether/verification_report.py +++ b/src/tether/verification_report.py @@ -63,7 +63,7 @@ def _format_parity(parity: dict[str, Any] | None) -> str: if not parity: return ( "## Parity\n\n" - "_Not yet verified._ Run `tether validate ` to populate.\n" + "_Not yet verified._ Run `tether validate export ` to populate.\n" ) summary = parity.get("summary", {}) or {} results = parity.get("results", []) or [] @@ -174,7 +174,7 @@ def write_verification_report( if model_id != "unknown": lines.append("```bash") lines.append(f"tether export {model_id} --target {target} --output ") - lines.append("tether validate ") + lines.append("tether validate export ") lines.append("```") lines.append("") lines.append(