Anchor plugin paths at PLUGIN_ROOT and restore the layer-filter caveat

The adapter delegated index preparation to Entry's Preparation step, but that
step is written for the clone model: it runs `pwsh ./tools/Build-KnowledgeIndex.ps1`
from the checkout root. A plugin host's working directory is the user's own
project, so the path does not resolve and the index is never built. Because
knowledge-index.json is gitignored, a fresh install has none, and READ silently
degrades to path-based discovery. The adapter now resolves Entry's repo-relative
paths against PLUGIN_ROOT and names the absolute index build; the generator
resolves its own root, so it indexes and writes the right tree from any cwd.

Entry also asserted that pruning has always happened before it runs, which is
false for an installation that ships the whole tree. Entry now scopes that
guarantee to consumers that actually prune, and the caveat dropped in the
rewrite - that enabled-layers narrows discovery rather than denying access - is
restored in the adapter and summarized in the README.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0b67b90d-e4b4-4b92-9684-726c72c43b3f
This commit is contained in:
Jesper Schulz-Wedde 2026-09-03 09:53:04 +02:00
parent 096f1c7b59
commit 045f4bccf1
3 changed files with 28 additions and 2 deletions

View file

@ -95,6 +95,11 @@ Entry remains the single owner of routing and index preparation;
separation keeps standalone installation available without duplicating those
policies in the plugin adapter.
Note that a plugin install ships the entire tree, so `BCQUALITY_ENABLED_LAYERS`
narrows discovery without removing any files. Layer selection is a filter here,
not a deny mechanism — see [the adapter](skills/al-code-review/SKILL.md) for the
difference from the pruned-clone model.
The host adapter and internal action skill intentionally share the
`al-code-review` name: they expose the same operation in two different skill
formats. Their paths make the boundary explicit. The adapter lives under

View file

@ -35,7 +35,15 @@ context and execute the resulting dispatch.
3. Read and execute `PLUGIN_ROOT/skills/entry.md` exactly as written, including
its Preparation step. Entry is authoritative for index freshness, routing,
defaults, and failure behavior; this adapter must not duplicate or weaken
those rules.
those rules. Entry is written for a checkout whose root is the current
directory, so resolve every repo-relative path it names against
`PLUGIN_ROOT` rather than the caller's working directory, which is the
user's own project. In particular, run Preparation's index build as
`pwsh PLUGIN_ROOT/tools/Build-KnowledgeIndex.ps1`: the generator resolves
its own root and writes `PLUGIN_ROOT/knowledge-index.json`, which is not
shipped and is therefore absent on a fresh install. If `pwsh` is
unavailable or the build fails, continue — READ falls back to path-based
discovery — but do not treat a failed build as a failed review.
4. Follow Entry's **How the agent uses the dispatch** instructions. Invoke only
the returned action skills, pass each dispatch entry's exact input subset,
and read `PLUGIN_ROOT/skills/read.md` and `PLUGIN_ROOT/skills/do.md` on
@ -48,3 +56,14 @@ The internal `microsoft/skills/review/al-code-review.md` action skill remains
the canonical coordinator for a broad AL review. Entry decides whether that
super-skill or a narrower domain skill applies; this host adapter never chooses
between them.
## Layer selection is not a deny mechanism
A plugin install ships the whole BCQuality tree, so `enabled-layers` here can
only narrow *discovery*: the files of a layer left out of the list still exist
on disk. This differs from the clone model Entry's Preparation step describes,
where a consumer prunes its checkout to policy before the agent runs and the
index is rebuilt over the pruned tree. Treat `BCQUALITY_ENABLED_LAYERS` as a
selection filter, never as a security boundary. A host that needs a genuine
deny mechanism must prune the installed tree itself.

View file

@ -35,7 +35,7 @@ task-context:
## Preparation — knowledge index
Before routing, ensure the knowledge index is current for the **live** clone. The dispatched review skills read `knowledge-index.json` (at the clone root) at their Source step instead of opening every knowledge file — see READ's [Retrieval workflow](read.md). Because a consumer prunes its clone to policy *before* the agent runs, the index MUST be built over the clone as it exists now, so it lists exactly the articles that survived pruning and never an article the consumer denied:
Before routing, ensure the knowledge index is current for the **live** clone. The dispatched review skills read `knowledge-index.json` (at the clone root) at their Source step instead of opening every knowledge file — see READ's [Retrieval workflow](read.md). When a consumer prunes its clone to policy *before* the agent runs, the index MUST be built over the clone as it exists now, so it lists exactly the articles that survived pruning and never an article the consumer denied:
- If `knowledge-index.json` is absent — or you cannot confirm it reflects the current knowledge tree — regenerate it by running, from the checkout root:
@ -44,6 +44,8 @@ Before routing, ensure the knowledge index is current for the **live** clone. Th
```
It defaults to indexing this checkout and writes `knowledge-index.json` at the root in well under a second. When in doubt, rebuild: a sub-second rebuild is always cheaper than a stale or over-listing index, which is a correctness risk.
- The paths above assume the checkout root is the current directory. A caller that enters Entry from elsewhere — a plugin host, whose working directory is the user's own project — MUST resolve them against the BCQuality root it already knows instead. The generator resolves its own root, so invoking it by absolute path indexes and writes the right tree.
- Pruning is the consumer's job, not Entry's, and not every consumer does it: an installation that ships the whole tree gets no deny guarantee from this step. There, `enabled-layers` narrows discovery only, and the unlisted layers' files remain on disk.
- This is a side step. It MUST NOT change Entry's output — the dispatch record below is the only thing Entry emits, and build logs are never part of the dispatch JSON.
Generation is **owned by BCQuality**: the generator ships here next to the skills and knowledge it derives from, and the consuming orchestrator neither builds nor knows about the index.