AGENTS.md@src/KyberWeave.Core · git:20260802.307d1a9 · 2026-08-02 · sha256 24c591aed3d144fe

AGENTS.md@src/KyberWeave.Core git:20260802.307d1a9A

Immutable. This exact content never changes and is served at /api/v1/blob/24c591aed3d144fe.

# KyberWeave.Core

The engine. Everything the CLI and the MCP server do is implemented here; those two are
thin hosts over this assembly.

Read [`/AGENTS.md`](../../AGENTS.md) first for repository-wide rules.

## Core does not construct its own collaborators

This is the constraint most easily broken by accident. Core defines **ports** and takes
them as constructor arguments or factories. **Composition roots** — `DocsCommandComposition`
in the CLI, `Program.cs` in the MCP server — decide which implementation is used.

`ICodeGraphResolver` is the worked example: Core consumes the interface, the CLI and MCP
host construct `CodeGraphResolverAdapter`, and tests inject `FakeCodeGraphResolver` so the
whole drift and join surface can be driven without `sqlite3` on the machine.

`DocumentIndexHost` takes `Func<ICodeGraphResolver>` and `Func<DocumentSet>` for the same
reason. If you find yourself newing up a loader or a resolver inside Core, the dependency
belongs in the caller.

## Layout

| Directory | Holds |
|---|---|
| `Docs/` | Parsing, search, validation, export, scaffolding — the DocGraph engine |
| `Skills/`, `Agents/` | Governance per artifact class |
| `Security/` | `InstructionSurfaceScanner`, shared by skill and agent scanning |
| `Diagnostics/` | `Diagnostic`, `DiagnosticReport`, `Severity` |
| `CodeGraph/` | Read-only port over the CodeGraph index |
| `Configuration/` | `kyber-weave.yml` loading and merging |
| `Text/`, `Parsing/` | Vectorizer, frontmatter reader |

## Rule ids live next to the code that raises them

Declared as `public const string` on the validator or linter that emits them, so the id
and the condition cannot drift apart. They are permanent — see the repository rules.

A `Diagnostic` carries `Code`, `Severity`, `Message`, `Subject`, `Path`, and `Hint`. Fill
the hint whenever the fix is knowable; `DocSpecValidator.Nearest` computes an edit-distance
suggestion and is offered only when the distance is plausibly a typo.

## Configuration merges by replacement

`OntologyConfigLoader.Merge` replaces lists rather than appending, and an **empty list is a
real value that clears the default** — `Clone` falls back only on null. That is how a host
drops the inherited `DevOps/*` exclusions. Preserve this when adding config keys, and add
the key to `OntologyYamlSection` with a hyphenated name.

## Child processes go through `ProcessRunner`

Never call `ReadToEnd()` on one redirected stream and then the other, and never call
`WaitForExit()` before draining both. An OS pipe buffer is finite, so a child that fills
the stream you are not currently reading blocks on write while you block on a read that
can never complete.

This is a silent bug — every fixture and happy path is quiet enough to fit in the buffer,
so it survives testing and hangs on the first talkative input. It had been written three
separate times in this repository before being centralised.

`Processes/ProcessRunner.ReadToEnd` starts both reads before awaiting either. Use it for
anything with `RedirectStandardOutput` or `RedirectStandardError`.
`ProcessRunnerTests` reintroduces the deadlock against a child that writes 300 KB to each
stream and fails on a timeout, so a regression is caught rather than hanging CI.

## Dependencies

Markdig and YamlDotNet only. Adding a third needs a stated reason — see the sqlite3
decision recorded in `CodeGraph/CodeGraphResolverAdapter.cs`.

`InternalsVisibleTo` exposes internals to `KyberWeave.Tests`, so helpers like link
normalization and vocabulary parsing are unit-tested directly rather than only through the
public command surface. Marking something `internal` does not put it beyond test reach.

## Documented behaviour

Several algorithms here are described in the governed corpus, and the description is
expected to stay true:

- Retrieval scoring, authority weighting, and budgeting — [`docs/docgraph/retrieval.md`](../../docs/docgraph/retrieval.md)
- The corpus/joins two-clock reload — [`docs/docgraph/architecture.md`](../../docs/docgraph/architecture.md)
- Every rule id — [`docs/ci-pipelines/rule-reference.md`](../../docs/ci-pipelines/rule-reference.md)

Changing a weight, a threshold, or a severity means updating those documents in the same
change. `docs_for_symbol` finds which ones claim the symbol you are editing.