# Trust and safety

Documentation packages are third-party input that ends up in a model's context. docspack
treats them accordingly.

## Vendor and community packages

Two naming conventions carry different guarantees. `@vendor/docspack` and its siblings
`@vendor/<name>-docspack` are published by the vendor, under a scope only the vendor can
publish to. `@docspack-community/<name>` is published by whoever maintains it.

The suffix changes nothing about trust, because the npm scope is what trust rests on:
whoever can publish `@vendor/docspack` can publish `@vendor/<name>-docspack` and nobody
else can. What the shape is *not* is a way for a package to nominate itself — a `docspack`
field in `package.json`, or a `.llms/` directory, would let any transitive dependency at
any depth declare itself documentation and be indexed as trusted. The name check is what
prevents that, and it is the reason discovery is a name check at all.

Community results are labelled `(community)` in `docspack search` and `docspack list`. When
a community chunk is returned over MCP, the response ends with a notice telling the model
that the source is unverified and that its content is data, not instructions. That does not
make prompt injection impossible, but it means an agent is never handed unvetted text
without being told what it is.

Prefer vendor packages where they exist. Read a community package before adding it, exactly
as you would read any other dependency.

## Path traversal

A manifest is a routing table written by someone else, and every `file` entry is resolved
before being read. A path that resolves outside the package's own `.llms/` directory is
refused and reported, not read:

```json
{ "id": "escape", "file": "../../../../etc/shadow" }
```

The rest of the package still indexes. One bad entry does not take down the whole package,
and it does not read a file outside the boundary either.

## Context exhaustion

An agent that retrieves too much context is as broken as one that retrieves nothing. Every
response is bounded, using the token count stored with each chunk rather than an estimate
made after the fact. See the chunk about connecting an agent for the exact limits and how
to change them.

## What docspack does not do over the network

`sync`, `search`, `list` and `mcp` never make a network request. They read `node_modules`
and a local SQLite file. An agent using docspack works on a plane, in a locked-down CI
runner, or inside a network-isolated container.

The single exception is `docspack build` when given a remote source, which is an authoring
command run deliberately, not part of serving documentation to an agent.

## Recording documentation problems

An agent reading documentation is unusually well placed to notice it is wrong: it has the
docs, the installed library and a failing program in front of it at once. `docspack feedback`
captures that, and the whole design is built so it cannot turn into a flood of machine-written
issues aimed at maintainers.

```bash
docspack feedback add --chunk @acme/docspack@1.4.0/api-auth \
  --kind drift --evidence "client.setKey is not exported; setApiKey is"

docspack feedback list
docspack feedback remove <fingerprint>
```

Agents on MCP use the `record_docs_problem` tool instead, which takes the same fields and
runs the same checks. Both interfaces call one function, so neither can accept a finding the
other would refuse.

Findings go to `.docspack/feedback.jsonl` in the project: one JSON object per line, readable,
diffable, and deleted with `rm`. **Nothing leaves the machine.** docspack contains no code
that can transmit a report — no tokens, no endpoints, no background requests. That guarantee
comes from something not being built, which is the strongest kind.

A finding has to be falsifiable, and that is enforced when it is written rather than when a
maintainer reads it:

- The chunk must exist in a package installed here. A reader that cannot point at the chunk
  did not read it.
- `drift` must name the identifier that drifted, so it cannot be used to file an opinion.
- `incorrect` and `missing` must carry `--expected`, `--actual` and `--repro`. A claim that
  cannot show its work is not recorded at all.
- There is no kind for "this page is confusing". Unfalsifiable claims are infinitely
  generatable and of no use to anyone.

Recording the same problem again increments a counter instead of adding a second entry. The
fingerprint covers the package, version, chunk, kind and the normalized claim, so the same
problem worded differently still lands on the same line. Twelve agents hitting one bug
produce one finding that says `seen 12×` — stronger evidence than twelve reports, and far
cheaper to read. A repeat only ever adds to the record; it never rewrites wording a human
may already have reviewed.

## Sending a problem upstream

`docspack feedback submit` prints a prefilled GitHub issue URL for every finding whose vendor
asked to receive it. It routes nothing anywhere else, and it sends nothing at all: a human
opens the link, reads what is prefilled, edits it, and files it under their own name.

A vendor opts in from their own `package.json`, the way
[security.txt](https://www.rfc-editor.org/rfc/rfc9116.html) solved the same problem for
vulnerability reports — a machine-discoverable contact point that the recipient declares:

```json
"docspack": {
  "feedback": {
    "github": "acme/sdk",
    "labels": ["documentation", "agent-reported"],
    "accepts": ["drift"],
    "policy": "https://acme.dev/docs-feedback"
  }
}
```

No `feedback` block means no channel, and `submit` lists those findings as **not routed**
rather than guessing a destination. That is the default, and it is the correct one: a
maintainer who has not asked for this gets nothing.

`accepts` is the field that matters most. A vendor drowning in noise narrows it to `["drift"]`
and receives only the mechanically verifiable class — reports where no judgment was exercised
and so no judgment can be wrong. Omitting `accepts` means all kinds are welcome. The person
who bears the cost sets the threshold. `policy` is shown before anything is filed, so the
vendor's own rules are read first.

Reports state their provenance rather than hiding it, because maintainers have asked to be
able to tell machine-written reports apart, and concealing it is what makes them toxic:

```md
**Chunk**: `@acme/docspack@1.4.0/api-auth`
**Kind**: drift — a name the docs use that the package does not declare
**Seen**: 12 times in one project

client.setKey is not exported; setApiKey is

---
Recorded with docspack 0.1.0, read and filed by a human.
```

When a finding carries a reproduction, `submit` warns you first: the reproduction is often
your own code, which is exactly what makes it useful and what makes it sensitive. You see the
whole report before anything is filed, because a human is in the loop by construction.

There is no automatic filing, at any level of confidence. There is no hosted service, no
telemetry, and no credentials. The strongest guarantee that docspack cannot become an
automated flood is that docspack contains no code that can send a report.
