Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
#!/usr/bin/env python3
"""The fleet table, regenerated from the sidecars rather than from memory.
A table of boards that someone updates by hand is a table that drifts, and the
one thing this fleet is for is knowing — without asking anyone — how many real
products the tool has actually carried to fab-ready. So the numbers come from
each board's own `main.board.json`, the file the pipeline writes and the
review loop gates on.
scripts/fleet-status # print the table
scripts/fleet-status --write # rewrite the table inside products/README.md
Never invents a row: a product with no sidecar is listed as "not built yet",
because a missing verdict and a passing one must not look the same.
"""
from __future__ import annotations
import argparse
import collections
import json
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
MARKER = "| Product | What it is | `fab.ready` | Blocking | In the app | Notes |"
def read_board(board_json: Path) -> dict:
try:
data = json.loads(board_json.read_text(encoding="utf-8"))
except (OSError, ValueError) as exc:
return {"error": f"{type(exc).__name__}: {exc}"}
warnings = (data.get("validation") or {}).get("warnings") or []
counts = collections.Counter(str(w.get("severity")) for w in warnings)
board = data.get("board") or {}
return {
"ready": bool((data.get("fab") or {}).get("ready")),
"blocking": counts.get("error", 0),
"warning": counts.get("warning", 0),
"info": counts.get("info", 0),
"width": board.get("widthMm"),
"height": board.get("heightMm"),
"bom": (data.get("bom") or {}).get("lines"),
"kinds": [w.get("kind") for w in warnings if w.get("severity") == "error"],
}
def describe(project: Path) -> str:
try:
product = json.loads((project / "product.json").read_text(encoding="utf-8"))
except (OSError, ValueError):
return ""
return str(product.get("description") or "").strip()
def installed_projects() -> dict[str, Path]:
"""Every product installed in the app, by the name the app shows.
The repo is not the product. A human opens
`~/.autonomous-circuit/projects/<uuid>`, and a table that only ever
measures `products/` can claim a readiness the app does not have — which
is exactly what happened: a round-4 panel judge found the repo saying
9 of 12 while the app held `two-key-footswitch` at its pre-fix 3 blocking,
`macropad-6` at its pre-fix 14, `pixel-badge` never built, and two products
not installed at all.
"""
root = Path.home() / ".autonomous-circuit" / "projects"
found: dict[str, Path] = {}
if not root.is_dir():
return found
for project in root.iterdir():
if not project.is_dir():
continue
try:
name = json.loads((project / "product.json").read_text(encoding="utf-8")).get("name")
except (OSError, ValueError):
continue
if name:
found.setdefault(str(name), project)
return found
def staleness(project: Path) -> str:
"""Whether the verdict describes the board beside it.
Ledger #42: a packet older than its own inputs still claims what it earned
under them. Ledger #39 is the same thing one level out — a golden block
moved its geometry and the board composing it was never rebuilt, so a
committed packet claimed `fab.ready: true` for a board that routes nothing.
**By content, not by clock.** The first version compared mtimes and cried
wolf the moment an engineer reverted a board to byte-identical source: the
bytes were the ones the verdict was earned on and the file was newer, so a
correct board was flagged. The sidecar already records
`source.fingerprint`, which folds the entry TSX, `product.json`,
`parts.json` and every local import including `blocks/` — so recomputing it
answers exactly the right question and answers it exactly.
"""
sidecar = project / "boards" / "main.board.json"
source = project / "boards" / "main.tsx"
if not sidecar.is_file() or not source.is_file():
return ""
try:
recorded = (json.loads(sidecar.read_text(encoding="utf-8")).get("source") or {})
except (OSError, ValueError):
return ""
if not recorded.get("fingerprint"):
return ""
try:
sys.path.insert(0, str(REPO / "packages" / "circuitpy" / "src"))
from circuitpy.source_hash import board_source_hash # noqa: PLC0415
identity = board_source_hash(source, project)
except Exception: # noqa: BLE001 - advisory; never break the table
return ""
if identity.source_fingerprint == recorded["fingerprint"]:
return ""
if identity.source_hash != recorded.get("hash"):
return "the board file changed and was never rebuilt"
# Same entry file, different graph: a block, the bible or the parts lock
# moved under it. This is ledger #39, and it is the one nobody notices.
return "a block or product.json changed under this board and it was never rebuilt"
def rows(root: Path) -> list[dict]:
out = []
installed = installed_projects()
for project in sorted(p for p in root.iterdir() if p.is_dir()):
sidecar = project / "boards" / "main.board.json"
row = {"slug": project.name, "what": describe(project), "stale": staleness(project)}
row.update(read_board(sidecar) if sidecar.is_file() else {"missing": True})
# And the same board as the app holds it.
live = installed.get(project.name)
if live is None:
row["app"] = {"missing": True}
else:
live_sidecar = live / "boards" / "main.board.json"
row["app"] = read_board(live_sidecar) if live_sidecar.is_file() else {"unbuilt": True}
out.append(row)
return out
def app_cell(row: dict) -> str:
"""The same board as the app holds it — the artifact a human opens."""
app = row.get("app") or {}
if app.get("missing"):
return "not installed"
if app.get("unbuilt"):
return "installed, never built"
if app.get("error"):
return "unreadable"
if app.get("ready"):
return "**yes**"
return f"no ({app.get('blocking', 0)})"
def table(items: list[dict]) -> str:
lines = [MARKER, "|---|---|---|---|---|---|"]
for row in items:
what = (row.get("what") or "").split(".")[0][:70]
if row.get("missing"):
lines.append(f"| `{row['slug']}` | {what} | — | — | {app_cell(row)} | not built yet |")
continue
if row.get("error"):
lines.append(f"| `{row['slug']}` | {what} | — | — | {app_cell(row)} | sidecar unreadable: {row['error']} |")
continue
size = ""
if row.get("width") and row.get("height"):
size = f"{row['width']:g} × {row['height']:g}mm"
note = size
if row["blocking"]:
kinds = collections.Counter(row["kinds"])
worst = ", ".join(f"{n}× {k}" for k, n in kinds.most_common(2))
note = f"{size} · {worst}"
if row.get("stale"):
note = f"{note} · ⚠ {row['stale']}"
lines.append(
f"| `{row['slug']}` | {what} | {'**yes**' if row['ready'] else 'no'} "
f"| {row['blocking']} | {app_cell(row)} | {note} |"
)
ready = sum(1 for row in items if row.get("ready"))
built = sum(1 for row in items if not row.get("missing") and not row.get("error"))
live_ready = sum(1 for row in items if (row.get("app") or {}).get("ready"))
live_built = sum(
1 for row in items
if not (row.get("app") or {}).get("missing") and not (row.get("app") or {}).get("unbuilt")
)
stale = [row["slug"] for row in items if row.get("stale")]
lines.append("")
lines.append(
f"**{ready} of {built} built boards are fab-ready** "
f"({len(items)} products in the fleet)."
)
lines.append("")
lines.append(
f"**In the app a human actually opens: {live_ready} of {live_built}.** "
"The repo is not the product — these are the same boards as installed under "
"`~/.autonomous-circuit/projects/`, and the two numbers parting company is a "
"finding, not a rounding. `scripts/install-fleet` closes the gap."
)
if stale:
lines.append("")
lines.append(
"**Verdict does not describe this board**: "
+ ", ".join(f"`{s}`" for s in stale)
+ ". Something under it changed and it was never rebuilt, so its numbers "
"were earned by a board that no longer exists — the entry file (ledger "
"#42) or a block, `product.json` or `parts.json` beneath it (ledger #39, "
"the one nobody notices). Compared by content, never by clock: a revert "
"to byte-identical source is not stale."
)
return "\n".join(lines)
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--write", action="store_true", help="rewrite products/README.md's table")
args = parser.parse_args(argv)
root = REPO / "products"
if not root.is_dir():
print("no products/ directory yet", file=sys.stderr)
return 1
rendered = table(rows(root))
if not args.write:
print(rendered)
return 0
readme = root / "README.md"
text = readme.read_text(encoding="utf-8")
at = text.find(MARKER)
if at == -1:
print("products/README.md has no fleet table to replace", file=sys.stderr)
return 1
readme.write_text(text[:at] + rendered + "\n", encoding="utf-8")
print(f"wrote {readme.relative_to(REPO)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
26e259c5cThis file is pinned to the selected release. Download the original to open it in your design tool.