Files
rustfs/AGENTS.md
T
Zhengchao An f84ba243a1 chore(ci): guard against committed planning docs and remove re-added ones (#4777)
chore(ci): guard against committed planning docs; remove re-added ones

PR #4771 removed the docs/superpowers planning-doc archive and added a rule,
but #4765 force-added two more (git add -f bypasses .gitignore):
docs/superpowers/plans/2026-07-12-observability-single-writer.md and
docs/superpowers/specs/2026-07-12-observability-single-writer-design.md — an
agentic implementation plan and its design spec. Delete both.

Close the enforcement gap so this cannot recur:
- New scripts/check_no_planning_docs.sh fails if anything is tracked under
  docs/superpowers/, regardless of how it was added.
- Wire it into make pre-commit/pre-pr/dev-check.
- Run it in CI: ci.yml for code/mixed PRs, and ci-docs-only.yml (which was a
  green stub) so docs-only PRs can no longer slip a planning doc past the
  required 'Test and Lint' check.
- Document the guard in AGENTS.md and the arch-checks skill.
2026-07-12 20:19:06 +08:00

289 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RustFS Agent Instructions (Global)
This root file keeps repository-wide rules only.
Use the nearest subdirectory `AGENTS.md` for path-specific guidance.
## Rule Precedence
1. System/developer instructions.
2. Current user/task instructions.
3. The nearest `AGENTS.md` in the current path.
4. This file (global defaults).
If repo-level instructions conflict, follow the nearest file and keep behavior aligned with CI.
## Execution Discipline
- Read the relevant existing code, tests, and local guidance before changing behavior.
- State assumptions when they affect the implementation or verification path.
- If a task has multiple plausible interpretations, list the options briefly and choose the narrowest reasonable path; ask when the ambiguity would make the change risky.
- For multi-step work, keep the plan minimal and tied to verifiable outcomes.
- Avoid redundant file reads, repeated commands, and unnecessary exploratory work once enough context is available.
- A good result is a minimal diff with clear assumptions, no over-engineering, and independent verification that survives Adversarial Validation (below).
## Communication and Language
- Respond in the same language used by the requester.
- Keep source code, comments, commit messages, and PR title/body in English.
- Be concise. Avoid sycophantic openers, closing fluff, and verbose status reporting.
## Change Style for Existing Logic
- Prefer direct, local code over extracting one-off helpers.
- Extract a helper only when logic is reused or the extraction materially clarifies a non-trivial flow.
- Use Rust's default module file layout (`mod foo;` with `foo.rs` or `foo/mod.rs`/`foo/*.rs`).
Avoid `#[path = "..."]` for module inclusion; move files into the canonical module tree instead.
If an unavoidable generated-code, FFI, or test-fixture exception remains, keep it local and document why the canonical layout cannot work.
- Solve only the requested problem; do not add speculative features, configurability, or adjacent improvements.
- Prefer editing existing code over rewriting files or reshaping unrelated logic.
- Modify only what is required and remove only artifacts introduced by your own changes.
- Preserve the existing control-flow and logic shape when fixing bugs or addressing review comments, especially in init, distributed coordination, locking, metadata, and concurrency paths.
- Do not refactor existing code only to make it easier to unit test.
- Keep fixes narrowly aligned with the requested behavior; avoid semantic-adjacent rewrites while touching sensitive paths.
- Keep code elegant, concise, and direct. Prefer minimal, readable implementations over over-engineering and excessive abstraction. Use comments to clarify non-obvious intent and invariants, not to compensate for unclear code.
- Mention unrelated issues when useful, but do not fix them as part of a narrow task.
## Constant and String Usage
- Before introducing new string literals, search for existing constants/enums that already represent the same semantic value.
- Reuse existing constants for protocol labels, error identifiers, header keys, event names, metric names, command tags, and similar fixed tokens.
- If a new string is truly unique, define a local constant near related logic and avoid scattering the literal across multiple sites.
- When changing existing behavior, keep naming and format consistency by aligning with established project constants.
## Sources of Truth
- Workspace layout and crate membership: `Cargo.toml` (`[workspace].members`)
- Local quality commands: `Makefile` and `.config/make/`
- CI quality gates: `.github/workflows/ci.yml`
- PR template: `.github/pull_request_template.md`
- High-level architecture and crate map: `ARCHITECTURE.md`
- Migration guardrails, readiness contracts, support matrices:
`docs/architecture/README.md` (routes by audience)
- Shared agent skills (all tools): `.agents/skills/` — each `SKILL.md` carries
a frontmatter `description` stating when it applies. Scan the descriptions
before starting a task and follow any skill that matches, even if your tool
does not auto-load skills:
`grep -m1 '^description:' .agents/skills/*/SKILL.md`
Claude Code reads them through the `.claude/skills` symlink; add new skills
to `.agents/skills/` only, never as separate copies per tool
Avoid duplicating long crate lists or command matrices in instruction files.
Reference the source files above instead.
Do not commit planning-type documents — one-shot implementation/optimization
plans, task trackers, migration-progress ledgers, phase/PR templates,
issue-scoped benchmark-result snapshots or optimization conclusions, or
agent-generated working notes (e.g. anything a `superpowers`/scratch workflow
produces). Keep that work in the issue tracker or your local worktree, not in
the repository. Only durable reference — the architecture set under
`docs/architecture/`, repeatable operational runbooks under `docs/operations/`,
and the test-suite references under `docs/testing/` — belongs in version
control; `.gitignore` ignores everything else under `docs/` by default, so a new
plan file will not be tracked unless someone force-adds it — don't.
`scripts/check_no_planning_docs.sh` (wired into `make pre-commit`/`pre-pr` and
CI) fails the build if anything is committed under `docs/superpowers/`, even via
`git add -f`.
## Verification Before PR
Convert changes into independently verifiable outcomes. Prefer focused tests for behavior changes and run the relevant checks before declaring completion.
Non-exempt changes must also pass Adversarial Validation (next section) before the checks below count as completion.
For code changes, run and pass the following before opening a PR:
```bash
make pre-pr
```
Before committing code changes, prefer focused verification for the touched
surface and use the faster local gate when a broad smoke check is needed:
```bash
make pre-commit
```
For migration batches, do not run the full `make pre-pr` gate before every
intermediate commit. Use focused tests and `make pre-commit` during
development, then reserve `make pre-pr` for the final PR-ready branch.
Before pushing code changes, make sure formatting is clean:
- Run `cargo fmt --all`.
- Run `cargo fmt --all --check` and ensure no files are modified unexpectedly.
If `make` is unavailable, run the equivalent checks defined under `.config/make/`.
Documentation-only or instruction-only changes are exempt from the verification commands above (including the `.config/make/` equivalents), though any locally installed git pre-commit hooks may still run on commit unless explicitly skipped.
After build-based verification completes, clean generated build artifacts before wrapping up to avoid unnecessary disk usage.
Do not open a PR with code changes when the required checks fail.
Make a failing check pass by fixing the cause, never by weakening the gate:
do not loosen or skip a guard script, add entries to a baseline or allowance
list, suppress a lint with `#[allow]`, mark a failing test `#[ignore]`, or
delete or relax a failing assertion to get green. If a check itself is wrong,
change it deliberately and state the rationale in the PR.
For flaky tests, do not paper over them with retries. Follow the flake policy
in [docs/testing/README.md](docs/testing/README.md) (open an issue within 24h,
quarantine with an issue link, fix or delete within 30 days); the local
`default` nextest profile never retries.
## Adversarial Validation (Default On)
Every non-exempt output (see Risk tiers) — code change, bug fix, or
design/solution proposal — passes multi-role adversarial review before it
counts as done.
Author confidence is not evidence: each role's job is to refute the change,
not to bless it.
### Risk tiers
Pick the tier from the riskiest file touched; when in doubt, pick the higher.
- **Exempt:** docs/comments/instruction-only changes, formatting, typos with
no runtime surface. Skip this section.
- **Mechanical:** pure renames, file moves, test-only or tooling changes —
correctness adversary only.
- **Standard (the default):** any change that affects behavior.
- **High risk:** touches locking, erasure coding, quorum/heal, replication,
multipart, RPC, lifecycle/tiering, metadata formats (`xl.meta`),
persistence/fsync, IAM/KMS/auth, on-disk or on-wire formats, or
S3 API-visible behavior.
### Roles
Run each applicable role as an independent pass over the final diff (or
proposal text) — parallel reviewer agents where the tooling supports them,
otherwise sequential passes that each start fresh from the diff and the
nearest scoped `AGENTS.md`, discarding the writing session's assumptions.
Each role either produces findings or reports "attacked X, Y, Z — no break
found"; a bare pass is not a result. Repo-specific attack probes for every
role live in `.agents/skills/adversarial-validation/` — run them, they
encode this repo's shipped bugs.
- **Correctness adversary** — construct a concrete input/state/interleaving
that yields wrong output, data loss, or a crash. Probe error paths and edge
values (empty, nil UUID, zero-length, quorum1, missing version). For code
diffs, a materially smaller or more idiomatic diff achieving the same
behavior is also a finding (see Change Style for Existing Logic).
- **Security reviewer** — authn/authz bypass, injection, secret leakage,
untrusted deserialization (see Serde Safety), path traversal, timing leaks.
- **Concurrency/durability reviewer** — lock ordering, races, cancellation,
partial failure, retry/idempotency, crash and power-loss ordering.
- **Compatibility reviewer** — S3 API surface, MinIO interop, on-disk and
on-wire formats, mixed-version upgrade/downgrade paths.
- **Performance reviewer** — allocation and cloning on hot paths, lock hold
time across IO, sync or CPU-heavy work on async runtime threads, added
fsync/flush outside the durability gate, hot-path logging noise. A
measurable regression on a per-request or per-object path is a finding.
- **Test-coverage skeptic** — for each claimed behavior, name the test that
fails if the change is reverted; then name a changed line that could be
wrong while all tests stay green — if one exists, coverage is insufficient.
A missing test is a finding, not a note.
Standard tier: correctness adversary + test-coverage skeptic, plus every
role whose domain the diff touches (async or shared-state code →
concurrency; parsing of untrusted input → security; public crate API shape
→ compatibility; per-request or per-object hot paths → performance).
High risk: all six roles.
### Protocol
1. A finding states a concrete failure scenario (input/state → wrong
outcome) or names a missing test, with severity and file:line. "Looks
risky" is not a finding.
2. Resolve every finding: fix it, or rebut it with evidence — a test, a
traced code path, or a cited invariant. Restated intent and "unlikely"
are not rebuttals.
3. After non-trivial fixes, re-run the roles whose domain the fix touched.
4. For proposals with no diff, roles attack assumptions, failure modes,
migration/rollback, and testability instead — including the simplest
rejected alternative and the blast radius when the design fails.
### Exit criteria
- Every applicable role has run; every finding is fixed or rebutted with
evidence.
- Every behavior change has a test that fails without it.
- The Verification Before PR gates pass — adversarial review supplements
those gates, never replaces them.
- High risk only: record a one-line verdict per role in the PR description.
## Git and PR Baseline
- Use feature branches based on the latest `main`.
- Assume other agent sessions work this repository concurrently. Never commit
in a shared checkout; do all work on a dedicated feature branch, preferably
in a dedicated worktree.
- Immediately before branching, fetch `origin/main` and branch from it;
confirm the target issue is not already fixed there before writing code.
- Follow Conventional Commits, with subject length <= 72 characters.
- Keep PR title and description in English.
- Use `.github/pull_request_template.md` and keep all section headings.
- Use `N/A` for non-applicable template sections.
- Include verification commands in the PR description.
- When using `gh pr create`/`gh pr edit`, write the markdown body to a file
and pass `--body-file`; multiline inline `--body` is unsafe — backticks and
shell expansion can corrupt content or trigger unintended commands.
Pattern: `cat > /tmp/pr_body.md <<'EOF' ... EOF`, then
`--body-file /tmp/pr_body.md` (keep the file outside the checkout).
- Do not include the literal sequence `\n` in any GitHub issue, pull request, or discussion comment.
- Do not hard-wrap prose in PR/issue/discussion bodies; write each paragraph as a
single line and let it reflow. GitHub renders single newlines inside a paragraph
as line breaks, so mid-sentence wrapping shows up as ugly breaks. Only break lines
for list items, code blocks, and deliberate separators.
- After fixing code review comments or CI findings, always mark corresponding review
comments/threads as resolved before returning to the user.
- In handling review comments, confirm the underlying issue before changing code.
If a suggested change is not appropriate for behavior or risk, reply with a
concise rationale instead of blindly applying it.
## Security Baseline
- Never commit secrets, credentials, or key material.
- Use environment variables or vault tooling for sensitive configuration.
- For localhost-sensitive tests, verify proxy settings to avoid traffic leakage.
## Tools
### xl.meta decode tool Quick Use
```
cargo run -p rustfs-filemeta --example dump_fileinfo -- "/path/to/file/xl.meta"
```
## Serde Safety
- Add `#[serde(deny_unknown_fields)]` to structs deserialized from untrusted input (S3 API XML/JSON, lifecycle rules, bucket policies, replication configs).
- When `deny_unknown_fields` is impractical (backward compatibility), at minimum log unknown fields at `warn` level.
- Never use `#[serde(default)]` on security-critical fields without explicit validation of the resulting value.
## Cross-Cutting Domain Invariants
- Write internal object metadata under **both** `x-rustfs-internal-<suffix>`
and `x-minio-internal-<suffix>` keys (MinIO interop). Use the helpers in
`crates/utils/src/http/metadata_compat.rs` (`get_bytes` prefers the RustFS
key); never write only one of the two.
- Read binary UUID metadata defensively:
`.and_then(|v| Uuid::from_slice(&v).ok()).filter(|u| !u.is_nil())`
absent, empty, and nil all mean "no value", never `Uuid::nil()`.
- A remote-tier version of `None`/`""` means the tier bucket is unversioned:
send **no** `versionId` on tier GET/DELETE.
## Naming Conventions
- Follow Rust API Guidelines for naming: `SCREAMING_SNAKE_CASE` for statics and constants, `snake_case` for functions and variables, `PascalCase` for types.
- Do not use camelCase or Hungarian notation (e.g., `globalDeploymentIDPtr``GLOBAL_DEPLOYMENT_ID`).
- If existing code violates naming conventions, do not widen the violation in new code. Do not rename existing symbols as part of an unrelated task; mention the violation instead (see Change Style for Existing Logic).
## Scoped Guidance in This Repository
Many crates and modules carry their own `AGENTS.md` with path-specific rules
(security boundaries, lock ordering, domain invariants). Before editing a
path, check for the nearest one:
```bash
git ls-files '*AGENTS.md'
```
The nearest file wins. Do not maintain a hand-written index of these files
here — it goes stale.