# Runner Path Projection — Slice 1 Plan (declared-rule only)

> **Status:** core helper implemented in `assay-runner-core`; not a
> shipped CLI or report contract. This narrows the path-projection work
> already described in
> [`projection-roadmap.md`](projection-roadmap.md) into the smallest
> buildable first slice. It does not change the Runner archive v0
> contracts, add a public CLI surface, infer heuristic classes, touch
> network projection, or promote projection output to primary evidence.
> The `assay.runner.path_projection.v0` and taxonomy schema strings used
> by the helper are internal projection labels at this stage, not a
> stable emitted artifact contract.

## Why a slice, not a new plan

The projection roadmap already defines the path classes, the network
taxonomy, the confidence levels, and the acceptance criteria. The
cross-runtime drift comparator already carries that taxonomy as
**vocabulary-only** metadata: it validates declared projection classes
and preserves `unknown`, but it does **not yet infer** a class from a raw
path or endpoint.

So the gap is not more planning. It is one bounded implementation step:
turn the documented taxonomy into a computed projection for the
highest-confidence case only. This slice scopes that step.

## Slice 1 scope

Implement path projection for **declared-rule mappings only**:

- workload-contract paths (declared input / output / scratch), and
- the run-workdir prefix when it is declared by workflow or artifact
  metadata.

Everything else stays `unknown`. No heuristics, no network, no taxonomy
inference beyond declared rules.

In scope:

```text
raw filesystem_paths (unchanged, still source of truth)
  + projected rows for declared matches only:
      raw_path, projected_path, path_class, rule, confidence=declared
  + unmatched raw paths summarized by count + samples, class=unknown
```

Explicitly **out of this slice** (later slices, same engine):

- Slice 2: heuristic path classes (`runtime_package`, `provider_sdk`,
  `loader`, `cache`) at `confidence=heuristic`.
- Slice 3: network endpoint projection (`provider_api`, `dns`,
  `telemetry`, `package_fetch`) reusing the same projection engine and
  confidence model.

## Output shape (extends the roadmap example)

```json
{
  "raw_path": "/opt/actions-runner/_work/assay/.../workdir/fixture-input.txt",
  "projected_path": "workdir/input",
  "path_class": "workload_fixture",
  "rule": "workload_contract_input_path",
  "confidence": "declared",
  "relation": "inside_run_workdir"
}
```

The raw `filesystem_paths` set is unchanged. Projected rows are additive.

## Acceptance rules

1. Raw path sets remain present and unchanged; projection is additive.
2. Every projected row carries `rule` and `confidence`.
3. Slice 1 emits `confidence=declared` only. A row that would require a
   prefix/substring heuristic is left `unknown`, not guessed.
4. Workdir-prefix stripping is allowed only when the prefix is declared
   by workflow or artifact metadata; an undeclared prefix stays raw.
5. Unmatched raw paths are summarized by count and samples; `unknown` is
   not a failure.
6. Projection is deterministic for this helper API: the same raw path
   set plus the same declared rules yields the same additive projection.
   The helper does not accept projection reports as input, so
   re-projecting projected output is out of scope for Slice 1.
7. Projection emits no policy verdict. `path_class` is reviewer
   vocabulary, not an allow/deny or safety judgment.
8. A report can show "raw paths differ, projected paths match" without
   asserting the workloads are semantically equivalent.

## Non-claims

- This slice does not classify a path as safe, malicious, expected, or
  policy-relevant. Class strings are reviewer vocabulary only.
- This slice does not infer heuristic classes; only declared rules
  produce a class in Slice 1.
- This slice does not change the Runner archive v0 schema, add a CLI
  surface, or promote projection to primary evidence.
- A projected match is not a claim of behavioral equivalence between two
  runs; raw rows remain the source of truth.
- `unknown` is an honest absence of a declared rule, not a finding.

## Slice gate (review-ready when)

- Declared-rule path projection emits additive rows with
  `confidence=declared` for the workload-contract and declared-workdir
  cases.
- Raw `filesystem_paths` round-trip unchanged.
- Determinism and `unknown`-preservation are covered by tests.
- A fixture shows "raw differs / projected matches" with the
  non-equivalence non-claim attached.

Slice 1 is implemented as a pure Rust helper in `assay-runner-core`.
It does not yet wire projection into a CLI, archive schema, stable
runtime-drift report emitter, or public schema artifact.
