# The stable toolchain's own binaries first: cargo finds its clippy and
# rustfmt on the PATH, where another install's (Homebrew's) can come first
# and lint with an older clippy than the check workflow's.
toolchain := `dirname "$(rustup which --toolchain stable cargo)"`
cargo := "env PATH='" + toolchain + ":" + env_var('PATH') + "' rustup run stable cargo"
ignore := "(tests/|harness/|examples/|rustlib/)"

# Install the reference PDS harness, the web pages' packages and coverage tools.
setup:
    cd harness && npm install --no-audit --no-fund
    cd web && npm install --no-audit --no-fund
    rustup component add llvm-tools-preview --toolchain stable
    command -v cargo-llvm-cov >/dev/null || cargo install cargo-llvm-cov

test:
    {{cargo}} test --workspace

# Tests while working: only those `args` pick, as cargo test takes them,
# against the harness `just pds` left running if there is one. For a change
# to the web pages, `just t -p knotless-serve --test web`.
t *args:
    KNOTLESS_TEST_NET={{justfile_directory()}}/target/test-net.json {{cargo}} test {{args}}

# The source files changed since tests last passed with `t-changed`, and
# the tests that cover them.
changed:
    @node harness/changed.mjs

# Runs the tests `changed` names, and marks them passed.
t-changed:
    @node harness/changed.mjs --run

# How the merge queue is doing, by day: queued to landed, ejections,
# batch times, what cancels checks, and tests passing only on a retry.
# `git fetch` first; `--days <n>`, `--json`, another `<handle>/<name>`.
queue-stats *args:
    @node harness/queue-stats.mjs {{args}}

# How a pull's files page does in a browser, loaded and read to its end:
# script, layout, long tasks, fetches. `just files-bench <page url>`;
# `--throttle 4`, `--nohl`, `--profile` (harness/files-bench.mjs).
files-bench *args:
    @node harness/files-bench.mjs {{args}}

# A reference PDS left running for tests to share, so each test binary
# need not start its own. Stop it with ctrl-c.
pds:
    mkdir -p target
    tail -f /dev/null | node harness/pds.mjs --accounts seed > target/test-net.json

# The same, against the spaces alpha.
test-spaces:
    KNOTLESS_DEV_ENV={{spaces}} {{cargo}} test --workspace

# The spaces alpha build of the reference PDS, for private repositories.
spaces := env_var_or_default("KNOTLESS_DEV_ENV", "../atproto-space-ref/packages/dev-env")

# Fails under 100% of lines or functions, over runs against the stock
# reference PDS and the spaces alpha together.
cov:
    node harness/cov.mjs '{{spaces}}' '{{ignore}}'

# Coverage over the stock run alone, failing on nothing: quicker than
# `cov`, but what only the spaces alpha reaches shows as missing.
cov-fast:
    KNOTLESS_DEV_ENV= {{cargo}} llvm-cov --workspace --ignore-filename-regex '{{ignore}}' --show-missing-lines

cov-html:
    {{cargo}} llvm-cov --workspace --ignore-filename-regex '{{ignore}}' --html --open

# The lexicons: goat's lint (github.com/bluesky-social/goat), less the two
# warnings kept on purpose (CLAUDE.md); what that lint does not see; that
# they only grow from main's; and that the XRPC answers the screenshots
# recorded are as they say.
lex:
    node harness/lexicons.mjs
    node harness/answers.mjs

# Docs links, anchors and diagrams; needs web/node_modules (npm ci in web/).
docs:
    node harness/docs.mjs

# The docs as the site at /docs serves them, at http://localhost:4321/docs/.
docs-site:
    cd docs-site && npm ci --no-audit --no-fund && npm run dev

lint:
    {{cargo}} fmt --all --check
    {{cargo}} clippy --workspace --all-targets -- -D warnings
    node harness/layers.mjs
    node harness/contrast.mjs
    cd web && npm run check

# Latency of agent operations at a given round-trip time, in milliseconds.
bench rtt="50":
    {{cargo}} build --release
    {{cargo}} run --release --example bench -- --rtt {{rtt}}

# What a social card costs to draw, stage by stage, and the PNGs, written
# to target/cards to look at.
bench-cards:
    {{cargo}} run --release -p knotless-serve --example cards -- --out target/cards

serve *args:
    {{cargo}} run --release -p knotless-serve -- {{args}}

# Builds the image on a host and restarts it there (deploy/README.md).
deploy *args:
    deploy/deploy.sh {{args}}

# What knotless logs on the host: `just logs serve 'select(.duration_ms > 1000)'`
# (deploy/logs.sh, deploy/README.md).
[positional-arguments]
logs *args:
    deploy/logs.sh "$@"

# Builds the client for every target and puts it on the host, for
# /install.sh to hand out (deploy/README.md).
release *args:
    deploy/release.sh {{args}}

# The web pages, built into web/build: a SvelteKit app that draws what
# knotless-serve answers as XRPC queries. Its types come from the lexicons.
web:
    cd web && npm run build

# The pages, from web/build, for `just serve --web http://127.0.0.1:2591`
# to hand them to, reading from that server.
pages: web
    HOST=127.0.0.1 PORT=2591 KNOTLESS_SERVE=http://127.0.0.1:2590 HOST_HEADER=x-forwarded-host PROTOCOL_HEADER=x-forwarded-proto node web/build

# The pages, redrawn as their source changes, reading from a
# `just serve` on its default port.
web-dev:
    cd web && npm run dev

# What moved in the pages since main: those whose HTML differs, shot as
# main draws them and as this checkout does (harness/shots/compare.mjs),
# each that moved left in target/shots/results to look at, as its
# expected, actual and diff. The pages are drawn from what
# harness/shots/fixtures.json recorded, so no PDS is needed. Arguments go
# to Playwright: -g ' profile$' for one page, or --project=desktop-light.
# SHOTS_BASE compares with another commit.
shots *args: web
    SHOTS_MOVED=all node harness/shots/compare.mjs {{args}}

# The same, failing on a page that moved but that no commit since main
# names on a `Shots-moved:` line, as the shots check fails on one its
# pull's body does not name.
shots-check *args: web
    node harness/shots/compare.mjs {{args}}

# A look at pages as this checkout draws them, in any state, as pictures
# in target/look to open: `just look pull-open`, `just look / --set
# 'getFeed.events=[]' --signed-in`, `--click 'details.popover summary'`.
# Drawn from harness/shots/fixtures.json, with no PDS; its options are at
# the top of harness/shots/look.mjs.
[positional-arguments]
look *args: web
    node harness/shots/look.mjs "$@"

# This checkout's pages drawn from the recording, against the same pages
# behind knotless-serve over a seeded PDS, the one `shots-up` keeps up if
# it is running: a page that moved is one whose recording is out of date.
shots-live *args: web
    {{cargo}} build --bins
    SHOTS_LIVE=1 node harness/shots/compare.mjs {{args}}

# The social cards, drawn by knotless-serve from a world, into
# target/shots/cards to look at.
shots-cards *args: web
    {{cargo}} build --bins
    cd harness && SHOTS_LIVE=1 npx playwright test -c shots/playwright.config.mjs --project=card --update-snapshots=all {{args}}

# The shots check as CI runs it: in Playwright's image, under Docker, as
# linux/amd64. Its node_modules are volumes of their own, as this
# machine's may not be Linux's.
shots-linux *args:
    docker run --rm --platform linux/amd64 -v "{{justfile_directory()}}":/w -w /w \
      -v knotless-shots-node:/opt/node -v knotless-shots-web:/w/web/node_modules \
      -v knotless-shots-harness:/w/harness/node_modules \
      mcr.microsoft.com/playwright:v1.58.2-noble bash harness/shots/linux.sh {{args}}

# Records again what knotless-serve answers for each page, from the world
# `shots-up` keeps up or a new one, into harness/shots/fixtures.json: after
# a change to what the server answers, or to the world.
shots-record: web
    {{cargo}} build --bins
    node harness/shots/fixtures.mjs

# The screenshots' PDS, seeded once and left running, so `shots` need only
# start the server. Stop it with ctrl-c.
shots-up: web
    {{cargo}} build --bins
    tail -f /dev/null | node harness/shots/world.mjs

# The pages used as people use them, in a browser: logging in through the
# PDS, then every write the pages make, each read back on the page and
# from the PDS (harness/e2e/flows.spec.mjs), over a world of its own seeded as the
# shots' is. Arguments go to Playwright: -g 'logging in through|starring'
# for one flow, after the login it needs.
e2e *args: web
    {{cargo}} build --bins
    cd harness && E2E=1 npx playwright test -c e2e/playwright.config.mjs {{args}}

# The private flows (harness/e2e/private.spec.mjs): a private repository
# used on the pages, over a world on the spaces alpha `spaces` names, a
# build of test.yml's ATPROTO_COMMIT.
e2e-private *args: web
    {{cargo}} build --bins
    cd harness && KNOTLESS_DEV_ENV={{spaces}} E2E=1 npx playwright test -c e2e/playwright.config.mjs {{args}}

# Agents doing a day's git work through the MCP server, one fresh session
# per step: `harness/scenarios/tracks`, or only the tracks named. Reports
# what tripped them up under target/scenarios/. Each run costs model usage.
scenarios *tracks:
    {{cargo}} build -q --workspace --bins
    node harness/scenarios.mjs {{tracks}}
