Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
- [ ] Code reviewed by human / 代码通过人工检查
- [ ] Changes tested / 已完成测试

<!-- Tick a box only if it actually happened. "Code reviewed by human" means a person reviewed it, not the author's
own agent. If an item does not apply, leave it unticked and add a short "N/A — why" line below the checklist,
so a reviewer can tell "not applicable" from "not done". -->

## Description / 描述

<!-- Description / PR 描述 -->
Expand Down
114 changes: 109 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ quick-map; concrete mechanics belong to the routed docs. Compatibility entry poi
separate contract. Use [`docs/README.md`](docs/README.md) as the index and follow the owning doc instead of
duplicating its rules.

When two instructions collide, the doc that owns the subject wins over a summary of it, a specific rule wins over
a general one, and a narrower exception wins over the default it names. If that still does not settle it, the
collision is itself a finding: take the more conservative reading, say which one you took, and report the conflict
so the doc set can be repaired — do not resolve it silently. A request from the user or a maintainer sets the goal
and authorizes the work, and it can waive a preference; it does not by itself satisfy a rule that this doc set
states as a prohibition. Say so once, in a sentence, and if the request is reaffirmed, carry it out and record it
in the change as a named, accepted deviation — never as compliance.

## Route the task before acting

| Before you… | Read |
| --- | --- |
| write code | [`docs/develop.md`](docs/develop.md) |
| modify tests, test helpers, or test runner configuration | [`docs/references/develop-testing.md`](docs/references/develop-testing.md) — apply the test-boundary, observation, and harness rules before editing |
| review or report a branch/PR, or create/update a PR or publish its branch | [`docs/develop.md#revision-scope-and-publication-binding`](docs/develop.md#revision-scope-and-publication-binding) + [`docs/pull-request.md`](docs/pull-request.md) |
| change a process/message/service/persistence boundary or add a subsystem | [`docs/architecture.md`](docs/architecture.md) + the relevant `docs/references/architecture-*.md` |
| build or modify a page, dialog, or block | [`docs/design.md`](docs/design.md) — Core Constraints apply to every UI change |
Expand All @@ -18,8 +27,10 @@ duplicating its rules.
| manually confirm a feature works | [`docs/verification.md`](docs/verification.md) — drive a throwaway session against the built extension, not the committed suite |

For tasks matching multiple rows, read every applicable owner before that work; do not front-load unrelated
docs. For tasks matching none, inspect `docs/README.md` and nearby implementation/tests before inventing a rule
or abstraction.
docs. Routing is continuous, not a classification you make once: when the work turns out to touch a row you did
not match at the start — a rename that crosses a persistence or message boundary, a UI fix that needs a new
entity — read that owner then, before continuing. For tasks matching none, inspect `docs/README.md` and nearby
implementation/tests before inventing a rule or abstraction.

## DeepWiki Context

Expand All @@ -38,16 +49,25 @@ These are repo-wide defaults. A linked, narrow exception in its owning doc is pa
downstream prose does not override it.

- **Fix root causes, not symptoms — refactor over patch.** No `as any`, `// @ts-ignore`, swallowed errors, or
defensive skips or try-catch swallowing (宁愿重构也不要打补丁). When a test fails, fix the code rather than the test, except for a wrong
test contract or valueless test as defined in
[`docs/references/develop-testing.md`](docs/references/develop-testing.md#writing-meaningful-tests-what-to-clean-up--not-write).
defensive skips or try-catch swallowing (宁愿重构也不要打补丁). When a test fails, fix the code rather than
the test, and never weaken an assertion to make it pass. Which failures are an exception — an obsolete contract, a
no-value test, a flake, work misclassified as a unit test — is decided by the classification table in
[`docs/references/develop-testing.md`](docs/references/develop-testing.md#cleaning-up-tests-safely), not by this
summary.
- **Confirm before fixing.** Reproduce and confirm a reported bug before changing it; capture the reproduction
first (确定 bug 存在 → 写测试或记录验证证据 → 修复). Use [`docs/verification.md`](docs/verification.md) and
the TDD principle in this section for the evidence standard.
- **TDD/BDD first for observable behavior.** Write a failing `describe`/`it` test before implementation, with
Chinese or English titles. The two narrow, non-blanket exceptions are in
[`docs/references/develop-testing.md`](docs/references/develop-testing.md#when-tdd-doesnt-apply); runner,
mocks, and how to run tests are in [`docs/develop.md`](docs/develop.md).
- **Test changes must follow the test route.** Before changing a test, shared test helper, or runner configuration,
identify the observable contract and test boundary, search existing coverage, capture a baseline or reproduction,
then make the smallest correction and rerun focused and relevant broader checks. A single passing run does not
establish a root-cause fix; report the trigger, evidence, and remaining uncertainty.
- **Shared E2E helpers must model both outcomes.** A helper that drives a save, install, or other mutation must make
the expected success or failure explicit and wait for that operation's matching signal. Negative cases must opt into
the failure contract; never make them pass by accepting an arbitrary toast, an old notification, or a page shell.
- **SOLID, high cohesion, low coupling.** Match existing extension points: persistence uses the small
`Repo<T>` / `DAO<T>` / `OPFSRepo` / custom-repo taxonomy, matching an existing entity with the same needs;
messages use `Group.on(...)`; service constructor shapes differ by context and Agent subsystem; depend on
Expand All @@ -74,6 +94,11 @@ downstream prose does not override it.
observations; normative specifications, compatibility contracts, security policies, accepted contracts or oracles, and
maintainer decisions determine correctness. A request/issue/PR does not prove a bug, necessity, or correctness.
Label inferences, unverified, and contradicted claims.
- **A change is material when a reviewer could not accept it from inspection alone.** That covers anything able
to alter runtime behavior, a public or persisted contract, security/privacy posture, permissions, cross-context
messaging, or build/release output. Everything else is routine and takes the light path: say what changed and
what you checked. Where the call is genuinely close, say which way you read it instead of quietly taking the
cheaper one.
- **State rationale before summary.** For material changes, connect problem/requirement → affected
scope/consequence → premise evidence → justification → remedy/trade-off → acceptance evidence → limitation/risk.
A diff shows what changed, not why.
Expand All @@ -82,6 +107,10 @@ downstream prose does not override it.
- **Match claim strength to evidence.** Static reasoning, executed tests, browser runs, and external integrations
prove different scopes. A negative claim needs the relevant channel observed through its closure window or a
causal proof that the side effect cannot occur.
- **Do not write a caveat you could have converted into a fact.** Before recording a concern, a risk, or a
"worth checking" note, check it — an unchecked worry moves the work to the reader and tells them nothing they
could not already guess. If you record one regardless, say why you did not check it and what would settle it.
Hedging is not caution when it costs the reader more than it saves you.
- **Bound readiness.** Do not call a material change review-ready with failed acceptance, a critical contradiction
or evidence gap, unjustified scope, or stale final-patch evidence. A requested draft/investigation may proceed
when labeled; report the blocker and clearing condition.
Expand All @@ -93,6 +122,81 @@ downstream prose does not override it.
useful location, and actionable contract to restore; do not turn an unverified repository assumption into a
finding.

## Autonomous operation

These govern what an agent does on its own between two human decisions — the acting as much as the bounds on it.
Within the work you were asked for you are the contributor, not a proposal generator: decide, do the work, and say
what you decided. Authority over the goal is not authority over every act taken to reach it, which is what the
later bullets bound.

- **Decide inside the scope you were given.** Three situations get confused as one. If you do not know something,
find out — read the code, run it, write the probe; a question you could have answered yourself is not a question.
If it cannot be known yet, take the cheapest reasonable reading, state the assumption where the work will be
read, and continue. Only the third is escalation: a decision needing authority you do not have — something
irreversible or outward-facing, a product or policy trade-off the maintainer owns, or accepting a residual risk
on their behalf. Difficulty, ambiguity, and ordinary risk are not authority problems. Resolve them and record how.
- **Hand a decision back only with its owner and its blocker named.** When you do escalate, say who owns the
decision, what specifically only they can supply, and what you will do by default if they say nothing. Without
those three it is not an escalation, it is unfinished work moved into someone else's queue. The same test governs
anything you notice in passing: if the task actually requires it, do it and say you did; if it merely happens to
be nearby, record a follow-up and move on — the boundary is the scope-discipline principle above, not the set of
files you happen to have open. Recommending work you were in a position to finish is not a lighter-touch option;
it is a smaller deliverable.
- **Stop and hand back rather than proceed on a broken premise.** Stop when the reported problem does not
reproduce, the confirmed cause lies outside the authorized scope, an observation contradicts the task's premise,
or the only remaining repair would remove supported behavior or violate a principle here. A failing check is not
one of these triggers — fix its cause. Stopping is a deliverable, not a failure: report the attempt, the
evidence, the contradiction, and the decision the human now owns. Do not substitute a smaller change that is
easier to justify for the one that was asked for. Submitting an explicitly requested draft or investigation
instead stays governed by [`docs/pull-request.md`](docs/pull-request.md#decision-evidence-and-readiness).
- **Bind the declared scope before committing or publishing.** The task statement, the commit type (gitmoji), and
the title declare a scope class — a test change, a fix, a refactor, a documentation change. Compare the actual
final diff against that class before you commit or push. Anything outside it is a checkpoint, not a judgement
call: move it into its own change with its own justification, or restate the scope. Do not carry an unexplained
edit forward because it looks harmless — a reviewer who cannot account for a hunk has to treat the whole change
as unreviewed. Mechanics live in [`docs/develop.md`](docs/develop.md#revision-scope-and-publication-binding).
- **Keep outward-facing and irreversible acts under explicit authorization.** Local work — reading, editing,
building, running the suite, driving a verification session — proceeds freely. Acts that leave the working tree
or are hard to undo need authorization for that specific act: pushing, opening or updating a pull request,
commenting on or closing an issue or pull request, deleting or rewriting a branch, and any command with real
external side effects. The task that asked for such an act is that authorization — this is not a rule to ask
permission twice — but a neighboring act it did not ask for is a separate decision.
- **Budget the reviewer's attention, not only your own.** An agent produces far more change per human review-minute
than a human contributor, so reviewability is part of the deliverable. Order the work so each commit is
independently reviewable and states the one thing it does; keep a confirmed behavior fix separate from cleanup
that merely travels with it; and when a correct repair is unavoidably large, say what makes it large and name
the seam a reviewer should check first.
- **Never let a provisional fix pose as the correct model.** The root-cause principle decides whether a
result-correct but mechanism-wrong change is acceptable at all; this decides what must be visible once one is
accepted anyway. A workaround taken for schedule, a compatibility shim, or a symptom suppressed with the cause
identified but unfixed must say so in the change itself — not only in a review thread later readers will not
see. A later agent reads merged code as the intended design and builds on it, so an unmarked workaround becomes
a false foundation that compounds.
- **Do not manufacture an oracle.** A self-generated score, grade, simulated pass rate, or persona review is your
own output, not an accepted oracle, and it cannot establish that a change is correct or good; report it, if at
all, as what it is. The same holds for an attestation that belongs to someone else — never record a human
review, a maintainer acceptance, or released behavior as satisfied on their behalf.

## Writing for a human reader

Everything an agent writes for people — pull request bodies, review comments, issue replies, hand-back reports — is
read by someone deciding what to do next. Being understood is part of delivering, and length is a cost the reader
pays rather than the writer.

- **Write to the reader's next decision.** They are deciding whether to merge, what to change, or what to look at
first. Anything that does not move that decision is padding, however true it is. Lead with the outcome and then
the reasoning; do not make the reader assemble the conclusion out of a narrative of how you reached it.
- **Prose is the default; structure has to earn its place.** A table of three sentences is harder to read than
three sentences. Headings, bullet lists, and severity labels help when the content is genuinely parallel or
enumerable, and get in the way when it is not. Match the shape of the write-up to the size of the change, not to
the longest template you were offered.
- **Say each thing once.** A fact repeated across sections is one fact and several copies, and a reader who notices
the copies differ now has to work out which is current. State it where it belongs and refer back.
- **Shorten by selecting, never by omitting.** Cut what does not change the reader's decision. Never cut a check
you ran, a limitation, an uncertainty, or evidence the change requires — dropping those is not concision, it is
an inaccurate report. And when emphasis is everywhere it is nowhere: reserve it for the one or two things you
would say aloud if you had the reader's attention for ten seconds.

## Architecture

Use [`docs/architecture.md`](docs/architecture.md) and its referenced deep-dives before changing a boundary or
Expand Down
10 changes: 10 additions & 0 deletions docs/DOC-MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ Every hit is a review-queue entry, not an automatic rewrite — confirm whether
correct (some are intentional non-negotiables) before loosening it, and confirm a downstream doc's exception
survives when you touch the upstream rule it narrows.

## Instruction budget

Agent-facing instructions are loaded on every task, so each rule carries a standing cost and competes for
attention with the rules already there. Before adding one, establish that it is not already derivable from a rule
present in the doc set, that it states a principle rather than replaying one incident, and that it belongs to the
doc that owns the subject rather than the doc most likely to be read. Prefer correcting or narrowing an existing
rule to appending a new one, and prefer one rule stated once in its owning doc to the same rule restated for
visibility — a rule that has to be repeated to be followed is usually stated in the wrong place. Deleting a rule
that a later rule superseded is maintenance, not loss of coverage.

## Lint / config documentation depth

When a doc describes an ESLint rule, tsconfig setting, or similar config-driven behavior, record the
Expand Down
3 changes: 2 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ premature abstraction.
test-first principle and [develop-testing.md § When TDD doesn't apply](./references/develop-testing.md#when-tdd-doesnt-apply)
for the narrow exceptions — this section only covers architecture-specific test mechanics, not the policy
itself.
- **E2E (Playwright).** `e2e/*.spec.ts`, one worker, real Chromium. `pnpm run test:e2e` (first run:
- **E2E (Playwright).** `e2e/*.spec.ts`, real Chromium; worker count and retries come from
[`playwright.config.ts`](../playwright.config.ts). `pnpm run test:e2e` (first run:
`pnpm run test:e2e:install`).
- **Before a PR:** lint + the relevant suite — owned by [references/develop-testing.md](./references/develop-testing.md) → *Testing*.

Expand Down
8 changes: 7 additions & 1 deletion docs/develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pnpm run coverage
pnpm run typecheck # tsc --noEmit

pnpm run test:e2e:install # install Playwright Chromium (first run only)
pnpm run test:e2e # Playwright (e2e/*.spec.ts, 1 worker)
pnpm run test:e2e # Playwright (e2e/*.spec.ts; worker count comes from playwright.config.ts)
pnpm run lint # prettier --check + tsc --noEmit + check:i18n + check:issue-templates, then eslint
pnpm run lint-fix # prettier --write + tsc --noEmit + eslint --fix

Expand Down Expand Up @@ -208,4 +208,10 @@ branch, bind the artifact, revision, and scope to the current remote state:
to its returned head SHA. Any new commit, force-push, rebase, base change, conflict resolution, or scope-claim
edit invalidates earlier evidence; rerun the affected review, checks, and final-diff audit.

The same binding applies to the scope you declared for your own change. A commit's gitmoji type and title, and the
task statement they serve, name a scope class; compare the final diff against that class before committing or
pushing. Move anything outside it into its own commit with its own justification, or restate the scope. A
production behavior change that arrives inside a test-cleanup or refactor commit is not reviewable as either, and
stays unreviewable no matter how correct it is on its own.

**Review policy**: review **all** modified files (including `.md`/`.json`); PR description is context only — judge from the diff. Verify every code path touched.
Loading
Loading