Build musl and glibc for amd64 and arm64 through one native package path. Reuse musl outputs for OCI images and OpenWrt installers, and export binaries inside a rootless unshare session. Restore the executable dependency graph into a shared persistent NuGet cache, build managed dependencies once, and run isolated native publishes in parallel. Clean temporary outputs and expired image layers under store locks, retire inactive legacy stores after seven days, and retain two toolchain exports. Add regression coverage for staging, extraction, packaging and cleanup boundaries.
90 lines
8.7 KiB
Markdown
90 lines
8.7 KiB
Markdown
# Agent Instructions
|
|
|
|
MoShiro is a self-hosted network path quality monitor. Agents on home broadband, NAT networks, or public VPS hosts run active measurements and record raw per-packet and per-event data. The Backend stores it, derives metrics, scores lines per service model, and serves a REST/SSE API to two web apps. Documentation is in Chinese under [`docs/`](docs/); source comments are mostly Chinese too. [`README.md`](README.md) is the entry point.
|
|
|
|
## Mental model
|
|
|
|
| Term | Meaning |
|
|
| --- | --- |
|
|
| Agent | Unified collector process (NativeAOT, BCL only), listening and dialing by default. Each Agent connects to the Backend over `wss` and reports outgoing link health and incoming sessions. |
|
|
| Line | One directed (dialer, listener) Agent pair, per IP family. Id `<agent_id>~<dialer_id>`, IPv6 adds `~ipv6`; series key `line:<dialer_id>` |
|
|
| Kind | A declared measurement method (`udp_echo`, `tcp_echo`, `connect`, ...) composed from building blocks. Defined once in `MoShiro.Protocol/Catalog/Kinds` |
|
|
| RawChunk | Self-describing columnar block, cut every 10 s, appended to segment files. The Backend never trusts node-reported statistics |
|
|
| Metric, Model | `MetricDef` is a one-line declaration over accumulators; models score metrics at query time. Both are recomputable from raw data |
|
|
| Plan | A sequence of on-demand test phases (for example `hy2_ladder`). Exists only in the Backend (`Application/Tests/Plans.cs`) |
|
|
| Fleet | Product-agnostic node framework under `backend/fleet/` (identity, enrollment, RPC, link, outbox, state sync) |
|
|
| Operator set | Passkey-signed trust root. Nodes pin its genesis fingerprint and owner at install time and verify the chain themselves |
|
|
|
|
## Invariants (violations fail the build or review)
|
|
|
|
- Node processes are kept to measurement and reporting by build-time restrictions: process start, dynamic loading, `HttpClient`, and file writes outside `Fleet.Hosting.ConfigStore` are banned (`backend/BannedSymbols.Node.txt`). Capabilities such as updates or command execution are not part of the core; adding or changing one needs a design review against `docs/security/security.md`.
|
|
- `backend/fleet/**` must not reference `MoShiro.*` (`ArchitectureTests`). `MoShiro.Measurement` contains no service concepts such as REALITY or Hysteria2.
|
|
- Every RPC method is declared in a method table (`FleetMethodTable`, `MoShiroMethodTable`) with direction, type and roles. Add the declaration before the handler.
|
|
- `Backend.Api` must not reference `Storage`. Error-code to HTTP mapping happens once, in the Api layer.
|
|
- Server-sent parameters pass `ParamSpec` validation and then the node-local hard limits (`BudgetGuard`). Never bypass either.
|
|
- Public API responses contain no IP, city or ASN.
|
|
- Code style is enforced at build time (`.editorconfig`, `BannedSymbols.txt`, warnings as errors). Details in [`docs/dev/coding-style.md`](docs/dev/coding-style.md).
|
|
|
|
## Where to change what
|
|
|
|
| Task | Location |
|
|
| --- | --- |
|
|
| New measurement method | Kind declaration in `backend/shared/MoShiro.Protocol/Catalog/Kinds`; new building block only if needed in `MoShiro.Measurement/Blocks` plus `BlockCatalog` |
|
|
| New metric | `MetricDef` in `backend/src/MoShiro.Backend.Analysis/Metrics`, add to `MetricRegistry.All` and a preset if shown |
|
|
| New service model | `Analysis/Models` |
|
|
| New RPC method | `MoShiro.Protocol/Rpc` (params, `MoShiroMethodTable`), then `router.On(...)` in `AgentApp`; Backend-side handlers register in `Backend.Gateway` (`FleetGateway`) |
|
|
| New REST endpoint | `Backend.Api/Public` or `Admin` (typed results, operationId, capability), contract DTO in `Api/Contracts`, then regenerate `backend/openapi/v1.json` and web types |
|
|
| New capability | `Capability` constants in `Backend.Application/Auth/Capabilities.cs`; every `/api/admin` endpoint must declare one |
|
|
| Schema change | Append a migration in `Storage.Sqlite/Schema.cs` and bump `CurrentVersion` |
|
|
| Agent-to-Agent connection states, retry cadence, health reporting | `backend/agent/src/MoShiro.Agent/Dial` (`DialConnection` control layer, `TaskLink` QUIC channel, `LinkStatus`), `LinkHealth` in `MoShiro.Protocol/Rpc`, [`docs/design/architecture.md`](docs/design/architecture.md) §4.3 |
|
|
| Install or update behaviour | `packaging/` (install scripts, Quadlet, compose, updater) and `docs/ops/deployment.md` |
|
|
| Web UI | `web/display` (anonymous read-only), `web/admin`, shared code in `web/shared`. Colors only in `web/shared/theme/tokens.css` |
|
|
|
|
## Documentation
|
|
|
|
Index: [`README.md`](README.md#文档). Prefer the code and `backend/openapi/v1.json` when they disagree with a document, and fix the document. Update docs in the same change as behaviour: `docs/design` (architecture, protocol, measurement, analysis, storage, query), `docs/security`, `docs/api`, `docs/ops`, `docs/dev`, and `docs/roadmap.md` for unimplemented work. Do not record dates or change history in docs.
|
|
|
|
Writing style for docs, READMEs, comments and commit messages (the `stop-slop` skill lists the patterns in detail; it is written for English, the same rules apply to Chinese):
|
|
|
|
- State the fact directly. Drop "not X but Y" contrasts, negation lists, rhetorical setups, and aphorisms that read like pull-quotes.
|
|
- Name the actor. Prefer "the Agent rejects the task" over "the task is rejected".
|
|
- No filler openers ("it is worth noting"), no closing summaries, no adverbs doing emphasis. Avoid bold for emphasis.
|
|
- Do not claim absolutes ("never", "always", "cannot") unless the code or a build-time check enforces it. Describe current behaviour and mark planned work as planned.
|
|
- Give concrete names, paths, values and commands instead of general statements.
|
|
|
|
## Workspace safety
|
|
|
|
- Inspect `git status` before editing. Preserve existing uncommitted changes; do not reset, clean, stash, or commit unrelated files.
|
|
- `main` is the only working branch. Commit to it directly; use a pull request when review is required.
|
|
- Never commit credentials, API keys, registry passwords, or generated runtime data. CI credentials are Woodpecker secrets (`zot_secret`, `gitea_token`, `release_signing_key`).
|
|
- The release signing private key must not enter the repository or the panel. Only the public key under `packaging/update/` is versioned.
|
|
|
|
## Build and test
|
|
|
|
Requirements: .NET SDK 10 (pinned by `global.json`) and Node.js with npm. NuGet versions are centralized in `Directory.Packages.props`.
|
|
|
|
| Task | Command |
|
|
| --- | --- |
|
|
| Build all .NET projects | `dotnet build MoShiro.slnx -c Release` |
|
|
| Backend tests | `cd backend && dotnet test --solution MoShiro.slnx -c Release` |
|
|
| Run Backend | `cd backend && dotnet run --project src/MoShiro.Backend -- --urls http://localhost:5000` |
|
|
| Web dependencies and build | `npm ci --prefix web && npm run build --prefix web` |
|
|
| Web dev servers | `npm run dev --prefix web` (ports are set in the Vite configs) |
|
|
| Style check | `npm run lint:css --prefix web` |
|
|
| Regenerate API types | `npm run gen:api --prefix web` |
|
|
|
|
First run of the Backend prints a claim code in its log; the admin UI asks for it. Slow end-to-end tests carry `[Trait("Category", "Slow")]`. After changing API contracts, update `backend/openapi/v1.json` and regenerate the web types. Run only the validation the task requires; do not start a full tag or release build unless requested.
|
|
|
|
## CI and releases
|
|
|
|
Triggers, tags and image paths are defined in `.woodpecker/*.yml` and [`docs/ops/deployment.md`](docs/ops/deployment.md). Verify them there before changing or describing them. The rules below are the stable contract.
|
|
|
|
- Every push to `main` runs the fast Backend tests and the web build. Both must pass before images are published.
|
|
- A commit message containing `[CI]` builds and pushes development images. `[CI SKIP]` skips the pipeline; `[SKIP TESTS]` skips only the Backend tests. Slow end-to-end tests run after image publication and do not block it.
|
|
- A tag `vMAJOR.MINOR.PATCH` runs the full cross-platform release pipeline. No version-bump commit is needed.
|
|
- Versions are produced by `ci/version.sh`. The `<Version>` in `backend/Directory.Build.props` and the `version` in `web` `package.json` files are placeholders (`0.0.0-dev`) and must not be edited.
|
|
- Linux Agent builds use `ci/build-linux-agent.sh` for musl/glibc on amd64/arm64 in both dev and tag workflows. OCI and OpenWrt installers reuse these native outputs; Windows runners build only Windows/macOS.
|
|
- Build stores keep NuGet cache mounts, retain image layers for 7 days, and clean temporary outputs under store locks (shared for native builds, exclusive for cleanup). Do not use `buildah prune` on these stores: it removes restore caches too.
|
|
- Development images use the `moshiro-dev/` repository path and release images use `moshiro/`. A development build must never overwrite a release tag such as `latest`.
|
|
- Release manifests are registered at `/api/release/offer`, which requires no token because the panel verifies the signature.
|