docs: document package model experience

This commit is contained in:
Tianyi Cui
2026-07-12 02:12:36 +08:00
parent 3dca90261c
commit 027970043c
75 changed files with 561 additions and 5 deletions

View File

@@ -15,7 +15,7 @@ Every fact has exactly one home — the tier whose job it is — and every other
| [rfc/](rfc/README.md) | Decision records: the why and the what-was-given-up; `implemented/` RFCs describe shipped reality in present tense | Migration plans, test checklists, and spec-speak ("should…") once the decision has shipped |
| [postmortem/](postmortem/README.md) | Incident stories — the only tier where war-story narrative belongs | — |
| [cookbook/](cookbook/adding-a-package.md) | Step-by-step how-tos with numbered verify steps | Design rationale (→ the RFC each guide links) |
| Package README | The per-package contract: config, semantics, limitations, extension points | JSDoc restatement, generated-catalog restatement (event/tool tables), other packages' concerns |
| Package README | The per-package contract: config, semantics, limitations, extension points, and [Model Experience](#package-model-experience) | JSDoc restatement, generated-catalog restatement (event/tool tables), other packages' concerns |
| [development.md](development.md) | First-stop contributor onboarding: local setup, daily workflow, and CI shape at summary level; a bilingual pair under the [i18n contract](i18n/README.md) | Runtime/version rationale (→ RFCs), gate-by-gate enumerations that drift from `package.json` scripts |
| Generated catalogs: [cordis events](cordis-catalog/events.md), [cordis services](cordis-catalog/services.md), [tool-catalog](tool-catalog.md), [config-catalog](config-catalog.md), [persistence-catalog](persistence-catalog.md), [module-graph.md](module-graph.md) | Exhaustive enumerations regenerated from source, freshness-gated | Hand edits of any kind |
| Skills (`.agents/skills/`) | Workflows: how to carry out a recurring task against the contracts | The contracts themselves (→ docs) |
@@ -33,6 +33,15 @@ Placement test: a story about a bug → postmortem. Why we chose X → RFC. How
- **Bilingual pairs update together**: editing either side obligates the counterpart and a re-record in the same change ([i18n contract](i18n/README.md)).
- Your audience is professional programmers. Prefer concise and straight-forward English over metaphor. Do not overuse words like "gate", "vocabulary", "surface", "seams".
## Package Model Experience
Every package README carries `## Model Experience` and this table:
| Context surface | What the model sees | Token effect |
|---|---|---|
Rows name the request surface and condition, including agent scope, then classify tokens as fixed per request, conditional per call, retained, replaced, capped, or zero-direct. Distinguish the conversation model from auxiliary calls. A zero-direct package names its indirect path. `verify-package-readme-model-experience` enforces shape; review owns accuracy.
## Wordcount Budgets
Every PR has a lesson it wants to append, and without pressure nothing leaves. [scripts/doc-budgets.manifest.json](../scripts/doc-budgets.manifest.json) stores the allowed word-count ceiling for each budgeted standing doc; `pnpm run verify-doc-budgets` fails when a doc exceeds its ceiling or a budgeted file is missing.

View File

@@ -13,9 +13,11 @@ packages/<group>/<pkg>/
# you use Config, + ../../<group>/<dep> for each dsh dep)
src/index.ts # service default export or plugin (name/inject/apply/Config)
tests/<x>.spec.ts
README.md # service API, events, extension points, design notes
README.md # contract plus the required Model Experience table
```
Fill the canonical [Model Experience table](../AGENTS.md#package-model-experience) from the implementation: name every direct request contribution and token-growth condition, or state zero direct tokens and the exact indirect path. Every package participates, including type-only libraries and backend seams.
Choose an existing group when one matches the package's role (`core`, `llm`, `bash`, `compact`, `subagent`, `todo`, `session-persistence`, `ui`, `util`, or `support`). A new group is allowed, but it is a pure container: no `package.json`, no source files, and packages still sit exactly one level below it.
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, `version: 0.0.1`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list is precise: `lib/index.js`, `lib/types/**/*.d.ts`, `lib/types/**/*.d.ts.map`, and `src`; do not publish `lib/types` JS or JS-map intermediates or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`.
@@ -41,6 +43,7 @@ For a swappable capability, split interface / implementation / consumer into sep
```sh
pnpm install # registers the workspace
pnpm run verify-package-readme-model-experience
pnpm run constraints && pnpm run typecheck && pnpm run lint
pnpm run test:coverage # 100% per-file over src (types.ts exempt)
pnpm run build && pnpm run hygiene

View File

@@ -161,6 +161,7 @@ Generated by `pnpm run gen-rfc-index` from the RFC tree — never edit by hand;
| [Raise the Node LTS engine floor to 22.19](implemented/process/2026-07-06-node-engine-floor.md) | 2026-07-06 |
| [Parallel GitHub CI gates](implemented/process/2026-07-06-parallel-github-ci-gates.md) | 2026-07-06 |
| [Parallel pre-push gates](implemented/process/2026-07-06-parallel-pre-push-gates.md) | 2026-07-06 |
| [Package Model Experience contract](implemented/process/2026-07-12-package-model-experience-contract.md) | 2026-07-12 |
### Testing

View File

@@ -0,0 +1,27 @@
# RFC: Package Model Experience contract
Status: implemented
## Problem
A package README can explain APIs and runtime mechanics without answering the question that dominates an agent harness's behavior and cost: what from this package reaches a model request, under which conditions, and how long those tokens remain. The omission is especially hard to audit in a plugin architecture. A consumer may turn a backend result into a tool message, a policy plugin may replace success with an error, compaction may remove old history, and an agent-scoped registration may change one agent's prompt or schemas while leaving every other agent unchanged. Reading only the nominally model-facing packages therefore misses real context effects, while reading source across every dependency is too expensive for routine review.
## Decision
Every workspace package README carries the canonical [Model Experience table](../../../AGENTS.md#package-model-experience). Each row identifies a concrete request surface, says what the relevant model literally receives and when, and classifies the token effect. The default subject is the conversation model; a package that invokes an auxiliary model, such as a summarizer or search provider, names that request separately. Agent-scoped visibility is stated where it changes which agent receives a contribution.
Every package participates. A service seam, storage backend, test helper, or type-only library that contributes no prompt text, tool schema, message, or auxiliary request records zero direct tokens and names the consumer or control path through which it can still change model-visible material. This explicit negative contract prevents readers from having to infer whether the section was forgotten.
`verify-package-readme-model-experience` discovers packages from `packages/*/*/package.json`, requires one sibling README, one exact `## Model Experience` heading, the canonical three-column table header, and at least one complete row. It runs in `doc-sync` and the parallel gate runner. The check owns shape and completeness; implementation review owns the truth of the prose.
## Alternatives considered
- **Document only packages that register prompts or tools** — rejected because backends, policy plugins, adapters, persistence, scoping, and compaction change the content or lifetime of tokens without owning a model-facing schema.
- **Generate one central context-cost catalog from source** — rejected because an AST can find registrations but cannot infer semantic conditions such as history retention, output truncation, parent-versus-child visibility, or an auxiliary model boundary. The package README is the implementation-local contract; a central copy would add another drift surface.
- **Require numeric token counts** — rejected because exact counts depend on the selected model tokenizer, adapter serialization, configuration, and runtime data. The stable contract is the growth shape: fixed per request, conditional per call, retained, replaced, capped, or zero-direct.
- **Allow zero-impact packages to omit the section** — rejected because absence is ambiguous between an audited zero and forgotten documentation. One explicit row is cheap and mechanically distinguishable.
- **Convention without a gate** — rejected because a repo-wide contract must also cover every future package; review memory cannot reliably detect an omitted README section.
## Consequences
A reviewer can start at any package and see its contribution to the conversation model, child models, and auxiliary calls without reconstructing the full plugin graph. Token-budget work can distinguish repeated request overhead from data-dependent history, and agent-scoped changes have an explicit documentation checkpoint. Package authors pay for one small table and must update it whenever model-visible behavior changes. The table deliberately does not promise provider-exact token counts; measurements remain model- and workload-specific, while the documented growth and visibility contract stays stable.