# Resolution-Completeness (#40 / #36b) Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use /ship (recommended) or /executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Make the gate's cross-file scope REACH first-party code it cannot see today on pnpm-workspace + barrel repos — by enumerating file-routed entry points from a filesystem fact and resolving `@scope/pkg` + barrel re-exports to the definition file.

**Architecture:** Two parts, ONE thesis — *prefer a filesystem/convention fact over a content-regex guess*. Part A (pilot) routes file-routed enumeration in `mapper.py` through the existing filesystem oracle (`FILE_ROUTE_RULES`) instead of the `onRequest`/`export const GET` content regex. Part B teaches `gate.py`'s resolver workspace aliases (pnpm-workspace.yaml + each package.json `exports`/`main`) and barrel re-export following, so a first-party `@zync/db` import resolves to the real definition file (which the existing `collect_deps` → `run_oracle_set` → `build_bundle` wiring then reaches automatically). **Pilot-before-fanout is MANDATORY: Part A lands and is MEASURED before any Part B code.**

**Tech Stack:** Python 3 (deterministic orchestrator, NO new deps — no PyYAML, no ts-morph), pytest, modules loaded by PATH via `importlib.util.spec_from_file_location` (NO `__init__.py`).

**SoT:** `docs/specs/2026-06-17-resolution-completeness-design.md` (advisor-passed, commit aa477b7). Prior art: `docs/specs/2026-06-17-band2-resolver-generalization-approaches.md` (#36), `docs/validation/2026-06-17-band2-delivery-shipped.md` (#36 deps-as-context), `docs/validation/2026-06-17-shapeB-scarcity-cross-repo.md` (Shape-B n=1/85 — why validation is COVERAGE, not a fabricated bug).

**Vocabulary (testing-native ONLY):** detector, domain, corpus, cell, canary, band, oracle, denominator, recall. NEVER module/layer/tier/seam as jargon.

**Commit discipline:** `command git add <specific files>` (tests/ and docs/ ARE tracked in this project). `command git commit` (RTK mangles commit messages — never routed). Terse caveman messages. Never co-author. Run tests with `rtk proxy python3 -m pytest`.

---

## Wave Plan

| Wave | Tasks | Files touched | Safe to parallelize? |
|------|-------|---------------|----------------------|
| 1 | Task 1 | orchestrator/mapper.py, bench.py, tests/test_mapper.py | single task (PILOT) |
| 2 | Task 2 | docs/validation/2026-06-18-partA-file-routed-measured.md | single task (measure pilot) |
| 3 | Task 3 | orchestrator/gate.py, tests/test_gate.py | single task |
| 4 | Task 4 | orchestrator/gate.py, tests/test_gate.py | single task (same files as T3 → later wave) |
| 5 | Task 5 | tests/test_gate.py | single task (deterministic plumbing gate) |
| 6 | Task 6 | docs/validation/2026-06-18-partB-resolution-coverage.md, domains/security/corpus/S1-barrel-2fa-on-refresh/* | single task (measure) |

Strict sequence: every wave is one task and each is blocked by the prior. Part B (Waves 3-6) is gated on Part A being **measured** (Wave 2), not merely built — pilot-before-fanout.

### Execution Ownership (read before dispatching)

All 6 waves are strictly sequential and Part B (Tasks 3-5) all share `gate.py`/`test_gate.py` → **ship's parallelism buys nothing here**; its only value is per-task review, done inline by the controller.

- **CONTROLLER-OWNED — do NOT blind-delegate:** Task 2 and Task 6 are MEASUREMENT + per-route human judgment, not code. Task 2 is the **pilot STOP gate** — "a dropped `http-file-route` that is a real route → STOP, do not proceed to Part B." A fire-and-forget subagent rubber-stamps the measurement and will not honor the stop. The controller runs the measurement command itself, inspects every dropped entry, and makes the gate decision. Same for Task 6 (per-package resolved/total + the #42 oracle-reach assertion are the controller's to confirm).
- **DELEGABLE (clean TDD code tasks):** Tasks 1, 3, 4, 5 — well-specified, test-first, single-file. Fine to dispatch to a Sonnet implementer with inline spec+quality review, OR execute inline. Either way the controller MUST personally run Task 2's measurement+gate before any Part B task and Task 6's measurement at the end.
- **Task 2 command form:** `--max-targets 0 --map <repo>` produces the surface map with zero dispatch (use this to read the enumerated set); `--dry-run` is a `gate.py` passthrough and never fires at `--max-targets 0`. Resolve any flag ambiguity by running it yourself.

---

## File Structure

- `orchestrator/mapper.py` (MODIFY) — add `_file_routed_kind(rel)` helper; route `actual_surface` (denominator) and `enumerate_surface` (numerator) for file-routed kinds through `FILE_ROUTE_RULES` (location); rework `file_routed_recall` to report location-based `within_kind_recall` (1.0 by construction) + a `retired_signal_recall` diagnostic.
- `orchestrator/conventions.py` (UNCHANGED) — `KIND_SIGNALS` stays intact (the `edge-function` `onRequest` row remains for the cross-kind denominator of call-registered counting; it just stops being an *enumerator*). `FILE_ROUTE_RULES` already has both file-routed kinds. No edit needed; a one-line comment update is optional and folded into Task 1 only if it aids clarity.
- `bench.py` (MODIFY) — update the `cmd_mapper` `note` string to state the post-Part-A meaning of `kind_coverage_by_volume` and `within_kind_recall`.
- `orchestrator/gate.py` (MODIFY) — add `_read_pnpm_workspace_globs`, `_read_npm_workspaces`, `_exports_target`, `_dist_to_src`, `_existing_source`, `build_workspace_aliases`, `find_repo_root` (Part B1); add `resolve_through_barrel` + `_barrel_named_source` + `_defines_local` and wire into `first_party_value_imports` (Part B2); wire `build_workspace_aliases` into `main()` with `--no-workspace-alias` / `--repo-root` flags.
- `tests/test_mapper.py` (MODIFY) — update `test_file_routed_recall_*`; add `test_edge_function_enumerated_by_location_not_content`.
- `tests/test_gate.py` (CREATE) — unit tests for `build_workspace_aliases`, `resolve_through_barrel`, and the deterministic plumbing gate (def body in bundle + oracle-set reaches resolved def file).
- `domains/security/corpus/S1-barrel-2fa-on-refresh/*` (CREATE, Task 6) — a barrel-wrapped variant of the real S1 canonical, used to confirm the known catch SURVIVES barrel indirection (NOT a new recall claim).

---

## Task 1: Part A — file-routed enumeration by LOCATION (PILOT)

**Wave:** 1
**Blocks:** Task 2
**Blocked by:** —

**Files:**
- Modify: `orchestrator/mapper.py` (`actual_surface` ~86-99, `enumerate_surface` ~102-127, `file_routed_recall` ~142-174; add `_file_routed_kind` near `_seg_route` ~130)
- Modify: `bench.py` (`cmd_mapper` `note` string ~125-130)
- Test: `tests/test_mapper.py` (update `test_file_routed_recall_surfaces_signal_miss_and_prunes_nested_git`; add `test_edge_function_enumerated_by_location_not_content`)

**Why this shape:** `KIND_SIGNALS` has TWO jobs — cross-kind denominator AND enumerator. Deleting the `edge-function` row would silently change what `kind_coverage_by_volume` measures. So we KEEP the row and only move the *enumerator* job: file-routed kinds (`http-file-route`, `edge-function`) enumerate from `FILE_ROUTE_RULES` (location); call-registered kinds keep content matching. Location ⊆ content (the 376/376 within-kind recall proves it), so the `http-file-route` count can only stay or DECREASE — every dropped entry must be inspected (a dropped real route is forbidden false-coverage).

- [ ] **Step 1: Write the new enumeration test (failing)**

Add to `tests/test_mapper.py`:

```python
def test_edge_function_enumerated_by_location_not_content():
    """Part A: file-routed kinds enumerate by LOCATION (filesystem oracle), not the content signal.
    A CF Pages function with the `export default` idiom (which the retired `onRequest` regex MISSED) IS
    enumerated because it lives under functions/. A file with `onRequest` OUTSIDE functions/ is NOT (the
    content signal is retired as an enumerator -> its false-positives vanish)."""
    d = tempfile.mkdtemp()
    os.makedirs(os.path.join(d, "functions/api"), exist_ok=True)
    os.makedirs(os.path.join(d, "src"), exist_ok=True)
    open(os.path.join(d, "functions/api/x.ts"), "w").write("export default async (r) => new Response('ok')")
    open(os.path.join(d, "src/mw.ts"), "w").write("export const onRequest = () => {}")  # off-location helper
    enumerated = {os.path.relpath(p, d) for p in (e.path for e in mapper.enumerate_surface(d))}
    assert "functions/api/x.ts" in enumerated      # location enumerates it despite export-default idiom
    assert "src/mw.ts" not in enumerated           # onRequest off-location no longer enumerated (FP gone)
```

- [ ] **Step 2: Run it — verify it fails**

Run: `rtk proxy python3 -m pytest tests/test_mapper.py::test_edge_function_enumerated_by_location_not_content -v`
Expected: FAIL — today `enumerate_surface` matches `onRequest` content anywhere, so `src/mw.ts` IS enumerated (assertion `not in` fails) and `functions/api/x.ts` (no `onRequest`/`GET` content) is NOT enumerated (assertion `in` fails).

- [ ] **Step 3: Add the `_file_routed_kind` helper**

In `orchestrator/mapper.py`, immediately AFTER `_seg_route` (~line 139), add:

```python
def _file_routed_kind(rel):
    """The file-routed kind whose FILE_ROUTE_RULES match this repo-relative path (a FILESYSTEM fact), or None.
    EXCLUDE_NONROUTE (framework `_`-private files, tests) are never routes. First kind in FILE_ROUTE_RULES
    insertion order wins. This is the single enumerator for file-routed kinds — content is NOT consulted."""
    if EXCLUDE_NONROUTE.search(rel):
        return None
    for kind, rules in FILE_ROUTE_RULES.items():
        if any(_seg_route(rel, segs, brx) for segs, brx in rules):
            return kind
    return None
```

- [ ] **Step 4: Route `actual_surface` (the cross-kind DENOMINATOR) through location for file-routed kinds**

Replace `actual_surface` (~86-99) with:

```python
def actual_surface(root):
    """INDEPENDENT denominator. File-routed kinds are counted by LOCATION (FILE_ROUTE_RULES); call-registered
    kinds by CONTENT (their KIND_SIGNALS regex). Pruned trees excluded. Returns [(abspath, kind)]. A file under
    a route location is that file-routed kind (location precedence); otherwise first content-matching
    call-registered kind wins (dict insertion order). KIND_SIGNALS rows for file-routed kinds are NOT consulted
    here — their job as a content enumerator is retired (Part A); the row remains only so the table still
    declares the kind."""
    file_routed = set(FILE_ROUTE_RULES)
    out = []
    for p in _walk_ts(root):
        rel = os.path.relpath(p, root).replace(os.sep, "/")
        fk = _file_routed_kind(rel)
        if fk is not None:
            out.append((os.path.abspath(p), fk))
            continue
        body = _read(p)
        if body is None:
            continue
        for kind, (rx, _reliable) in KIND_SIGNALS.items():
            if kind in file_routed:
                continue  # counted by LOCATION above, never by content
            if rx.search(body):
                out.append((os.path.abspath(p), kind))
                break
    return out
```

- [ ] **Step 5: Route `enumerate_surface` (the NUMERATOR) through location for file-routed kinds**

Replace `enumerate_surface` (~102-127) with:

```python
def enumerate_surface(root):
    """The mapper's ACTUAL discovery. File-routed kinds enumerate by LOCATION (FILE_ROUTE_RULES) — every route
    file is enumerated regardless of its registration idiom (so the CF Pages `export default` idiom that the
    retired `onRequest` regex missed is now caught, and that regex's off-location false-positives are gone).
    Call-registered kinds enumerate by CONTENT (signal primary; path_glob only annotates why/priority).
    CONSEQUENCE: per-file-routed-kind within-kind recall is 1.0 BY CONSTRUCTION (enumerate == the filesystem
    oracle); for call-registered kinds the ~1.0 is structural (grep is best-available truth, no oracle)."""
    file_routed = set(FILE_ROUTE_RULES)
    rows_by_kind = {}  # call-registered rows only
    for c in CONVENTIONS:
        if c["kind"] in file_routed:
            continue
        rows_by_kind.setdefault(c["kind"], []).extend(c["path_globs"])
    out = []
    for p in _walk_ts(root):
        rel = os.path.relpath(p, root).replace(os.sep, "/")
        fk = _file_routed_kind(rel)
        if fk is not None:
            out.append(Entry(os.path.abspath(p), fk, f"route:{fk}"))
            continue
        body = _read(p)
        if body is None:
            continue
        for kind, globs in rows_by_kind.items():
            rx, _ = KIND_SIGNALS[kind]
            if rx.search(body):
                in_glob = any(fnmatch.fnmatch(p.replace(os.sep, "/"), g) for g in globs)
                out.append(Entry(os.path.abspath(p), kind, f"signal:{kind}" + ("+glob" if in_glob else "+offpath")))
                break
    return out
```

- [ ] **Step 6: Rework `file_routed_recall` to report location-recall + a retired-signal diagnostic**

Replace the per-kind output block of `file_routed_recall` (~155-174) with:

```python
def file_routed_recall(root):
    """WITHIN-KIND completeness for file-routed kinds. After Part A enumeration is BY LOCATION, so within_kind_recall
    = enumerated/fs_routes is 1.0 BY CONSTRUCTION. `retired_signal_recall` = content_signal_hits/fs_routes is a
    DIAGNOSTIC of the now-retired content regex: how many location-routes that regex WOULD have matched. A
    retired_signal_recall < 1.0 is exactly the recall the content signal lost (e.g. the CF Pages export-default
    idiom) and is the empirical justification for switching to location. missed_sample = location routes NOT
    enumerated (must be empty post-Part-A; a non-empty set is a FILE_ROUTE_RULES bug, surfaced not silenced)."""
    enr = {e.path for e in enumerate_surface(root)}
    out = {}
    for kind, rules in FILE_ROUTE_RULES.items():
        rx, _ = KIND_SIGNALS[kind]
        fs_routes = content_signal_hits = enumerated = 0
        missed = []
        for p in _walk_ts(root):
            rel = os.path.relpath(p, root).replace(os.sep, "/")
            if EXCLUDE_NONROUTE.search(rel) or not any(_seg_route(rel, segs, brx) for segs, brx in rules):
                continue
            fs_routes += 1
            body = _read(p)
            if body is not None and rx.search(body):
                content_signal_hits += 1
            if os.path.abspath(p) in enr:
                enumerated += 1
            else:
                missed.append(rel)
        out[kind] = {
            "fs_routes": fs_routes,
            "enumerated": enumerated,
            "content_signal_hits": content_signal_hits,
            "within_kind_recall": round(enumerated / fs_routes, 3) if fs_routes else None,
            "retired_signal_recall": round(content_signal_hits / fs_routes, 3) if fs_routes else None,
            "missed_sample": sorted(missed)[:10],
        }
    return out
```

- [ ] **Step 7: Update the existing file-routed test to the new (location) semantics**

Replace `test_file_routed_recall_surfaces_signal_miss_and_prunes_nested_git` body's assertions (~81-86) with:

```python
    fr = mapper.file_routed_recall(d)
    hfr = fr["http-file-route"]
    assert hfr["fs_routes"] == 2                         # both files are route-LOCATED
    assert hfr["within_kind_recall"] == 1.0              # LOCATION enumerates BOTH (incl the export-default one)
    assert hfr["retired_signal_recall"] == 0.5          # the retired content regex would have caught only 1/2
    assert hfr["missed_sample"] == []                    # nothing missed by location -> no offender
    assert fr["edge-function"]["fs_routes"] == 0         # the nested-worktree copy is pruned, not counted
```

(The fixture is unchanged: `src/pages/api/orders.ts` = `export const GET` content hit; `src/pages/api/subscribe.ts` = `export default` — the idiom the content regex misses but LOCATION catches. This now PROVES the Part A thesis directly.)

- [ ] **Step 8: Update the bench `note` string to the post-Part-A meaning**

In `bench.py` `cmd_mapper`, replace the `"note"` value (~125-130) with:

```python
        "note": "kind_coverage_by_volume = enumerated/actual: share of detected entry points whose KIND the mapper "
                "enumerates. File-routed kinds (http-file-route, edge-function) are counted by LOCATION "
                "(FILE_ROUTE_RULES) on BOTH sides; call-registered kinds by CONTENT signal. Per-enumerated-kind "
                "recall is 1.0 BY CONSTRUCTION; this only shows no-row kinds as misses. within_kind_recall (file-routed "
                "only) is now LOCATION-based and 1.0 by construction; retired_signal_recall shows how lossy the old "
                "content signal was. canonical_confirmation is SECONDARY and gated on the source repo; never read a "
                "gated value as recall.",
```

- [ ] **Step 9: Run the full mapper suite + new test**

Run: `rtk proxy python3 -m pytest tests/test_mapper.py -v`
Expected: all 7 existing tests PASS (the 4 call-registered/coverage-map tests unaffected; `test_file_routed_recall_*` passes with new assertions; `test_bench_mapper_*` skips or passes — its `within_kind_recall==1.0` assertion still holds) + the new `test_edge_function_enumerated_by_location_not_content` PASSES. 8 passed (or 7 passed + 1 skipped if multideal not checked out).

- [ ] **Step 10: Commit**

```bash
command git add orchestrator/mapper.py bench.py tests/test_mapper.py
command git commit -m "#40 Part A: file-routed enumeration by location, not content regex"
```

---

## Task 2: Part A measurement — pilot result on multideal (gate before fan-out)

**Wave:** 2
**Blocks:** Task 3
**Blocked by:** Task 1

**Files:**
- Create: `docs/validation/2026-06-18-partA-file-routed-measured.md`

**Why:** Pilot-before-fanout. Part B does NOT start until Part A's effect on a real tree is measured and inspected. The `http-file-route` count can only stay or decrease; every dropped entry must be confirmed a non-route.

- [ ] **Step 1: Measure edge-function enumeration on multideal**

Run: `rtk proxy python3 orchestrator/mapper.py /home/user/Projects/multideal --map /tmp/partA_map.json --max-targets 0 --dry-run` — if `--dry-run` is rejected by mapper argparse (it passes through to gate.py), instead run the bench mapper path:

Run: `rtk proxy python3 bench.py --mapper /home/user/Projects/multideal`
Expected: JSON. Record `by_kind["edge-function"]` and `within_kind_recall["edge-function"]`. EXPECT `edge-function` actual == 2 (multideal `functions/` holds exactly `functions/api/subscribe.ts` + `functions/api/subscribe.js` — verified 2026-06-18) and `within_kind_recall["edge-function"]["within_kind_recall"] == 1.0` with `retired_signal_recall` < 1.0 (the export-default idiom the old `onRequest` regex missed).

- [ ] **Step 2: Measure http-file-route BEFORE vs AFTER**

The BEFORE number is the content-enumeration count from the prior committed mapper (git-recoverable). Compute AFTER from the same `bench.py --mapper` run: `by_kind["http-file-route"]["enumerated"]`. To get BEFORE without reverting, count content hits directly:

Run: `rtk proxy python3 -c "import importlib.util,os; spec=importlib.util.spec_from_file_location('m','orchestrator/mapper.py'); m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m); print(len([1 for p,k in m.actual_surface('/home/user/Projects/multideal') if k=='http-file-route']))"`
Compare to the retired_signal vs location counts in the `within_kind_recall` block. Record AFTER (location) and the retired content count.

- [ ] **Step 3: INSPECT every dropped http-file-route entry**

If AFTER < the retired content count, list the dropped files (content matched `export const GET/POST` but is NOT route-LOCATED). For EACH dropped path, open it and confirm it is genuinely not a route (`FILE_ROUTE_RULES` models `pages/api/**` and `app/**/route.ts` only). A dropped REAL route = forbidden false-coverage → STOP, add the missing rule to `FILE_ROUTE_RULES` in a follow, do not proceed. Record each drop + verdict.

Run (find the drops): `rtk proxy python3 -c "<load mapper>; ... print set difference of content-GET/POST files minus location-routed files"` (use `actual_surface` content vs `file_routed_recall` fs_routes; print repo-relative paths).

- [ ] **Step 4: Write the measurement doc**

Write `docs/validation/2026-06-18-partA-file-routed-measured.md` (audience: AI coding agents first) with: edge-function actual + within_kind_recall + retired_signal_recall; http-file-route BEFORE (content) vs AFTER (location) with the EXACT measured numbers; the dropped-entry table (path + verdict: helper/test/private vs real-route); the verbatim post-Part-A meaning of `kind_coverage_by_volume` (mirror the bench note). State plainly whether any real route was dropped (must be NO to proceed).

- [ ] **Step 5: Commit**

```bash
command git add docs/validation/2026-06-18-partA-file-routed-measured.md
command git commit -m "#40 Part A measured: multideal edge-function 2/2, http-file-route drops inspected"
```

---

## Task 3: Part B1 — workspace-aware resolver (pnpm-workspace + package.json exports)

**Wave:** 3
**Blocks:** Task 4
**Blocked by:** Task 2

**Files:**
- Modify: `orchestrator/gate.py` (add helpers above `resolve` ~46; wire into `main()` ~315-320; add CLI flags ~293-315)
- Create: `tests/test_gate.py`

**Why:** Today `resolve()`'s candidate list `(p+".ts", p+".tsx", p, p+"/index.ts")` MISSES a barrel at `src/index.ts` and has no `@zync/*` aliases at all → every first-party workspace import resolves to None. `build_workspace_aliases` reads the workspace facts (pnpm-workspace.yaml globs → package.json `name` + `exports`/`main`) and returns the `[(prefix, root)]` shape `resolve()` already consumes.

- [ ] **Step 1: Write the failing workspace-alias test**

Create `tests/test_gate.py`:

```python
"""test_gate.py — deterministic gate for the cross-file resolver (Part B). Loads gate.py by PATH
(project convention — no package import, no __init__.py)."""
import importlib.util, os, tempfile, json

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def _load(name, path):
    spec = importlib.util.spec_from_file_location(name, path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


gate = _load("sg_gate", os.path.join(ROOT, "orchestrator", "gate.py"))


def _ws_tree():
    """A pnpm workspace: packages/db with exports['.']->src/index.ts and ['./queries']->src/queries/index.ts,
    plus a built package whose exports point at dist/ (must remap to the src/ twin)."""
    d = tempfile.mkdtemp()
    open(os.path.join(d, "pnpm-workspace.yaml"), "w").write("packages:\n  - 'packages/*'\n")
    db = os.path.join(d, "packages/db/src/queries")
    os.makedirs(db, exist_ok=True)
    open(os.path.join(d, "packages/db/package.json"), "w").write(json.dumps({
        "name": "@zync/db", "type": "module",
        "exports": {".": "./src/index.ts", "./queries": "./src/queries/index.ts"},
    }))
    open(os.path.join(d, "packages/db/src/index.ts"), "w").write("export { createDb } from './client'")
    open(os.path.join(d, "packages/db/src/queries/index.ts"), "w").write("export const tenantQuery = () => {}")
    built = os.path.join(d, "packages/built/src")
    os.makedirs(built, exist_ok=True)
    open(os.path.join(d, "packages/built/package.json"), "w").write(json.dumps({
        "name": "@zync/built", "exports": {".": "./dist/index.js"},
    }))
    open(os.path.join(d, "packages/built/src/index.ts"), "w").write("export const x = 1")  # the src twin
    return d


def test_build_workspace_aliases_resolves_bare_and_subpath_and_dist_remap():
    d = _ws_tree()
    aliases = gate.build_workspace_aliases(d)
    amap = dict(aliases)
    assert amap["@zync/db"] == os.path.join(d, "packages/db/src/index.ts")            # bare -> barrel
    assert amap["@zync/db/queries"] == os.path.join(d, "packages/db/src/queries/index.ts")  # subpath -> direct
    assert amap["@zync/built"] == os.path.join(d, "packages/built/src/index.ts")      # dist -> src remap
    # subpath specifier (longer) must sort BEFORE the bare name so resolve()'s exact match picks it
    keys = [s for s, _ in aliases]
    assert keys.index("@zync/db/queries") < keys.index("@zync/db")


def test_resolve_uses_workspace_alias_for_bare_specifier():
    d = _ws_tree()
    aliases = gate.build_workspace_aliases(d)
    f = gate.resolve("@zync/db", os.path.join(d, "packages/db"), aliases)
    assert f == os.path.join(d, "packages/db/src/index.ts")
    f2 = gate.resolve("@zync/db/queries", os.path.join(d, "packages/db"), aliases)
    assert f2 == os.path.join(d, "packages/db/src/queries/index.ts")
```

- [ ] **Step 2: Run it — verify it fails**

Run: `rtk proxy python3 -m pytest tests/test_gate.py -v`
Expected: FAIL with `AttributeError: module 'sg_gate' has no attribute 'build_workspace_aliases'`.

- [ ] **Step 3: Implement the workspace-alias helpers**

In `orchestrator/gate.py`, add `import glob, json` to the top import line (currently `import argparse, os, re, subprocess, sys, tempfile, concurrent.futures as cf`), then add ABOVE `resolve` (~line 46):

```python
def _read_pnpm_workspace_globs(repo_root):
    """Parse the `packages:` list from pnpm-workspace.yaml WITHOUT a YAML dep (deterministic Python-only gate).
    Handles the only shape in evidence: a top-level `packages:` key, then `- '<glob>'` list items."""
    p = os.path.join(repo_root, "pnpm-workspace.yaml")
    if not os.path.isfile(p):
        return []
    globs, in_pkgs = [], False
    for line in open(p, encoding="utf-8", errors="replace"):
        s = line.rstrip("\n")
        if re.match(r"^packages:\s*$", s):
            in_pkgs = True
            continue
        if in_pkgs:
            m = re.match(r"\s*-\s*['\"]?([^'\"#]+?)['\"]?\s*(?:#.*)?$", s)
            if m:
                globs.append(m.group(1).strip())
            elif s and not s[0].isspace():  # next top-level key ends the list
                break
    return globs


def _read_npm_workspaces(repo_root):
    """Best-effort npm/yarn `workspaces` globs from the root package.json (NOT measured — pnpm is the validated
    path). Supports both the array form and the {packages:[...]} object form."""
    pj = os.path.join(repo_root, "package.json")
    try:
        data = json.load(open(pj, encoding="utf-8"))
    except (OSError, ValueError):
        return []
    ws = data.get("workspaces")
    if isinstance(ws, list):
        return [g for g in ws if isinstance(g, str)]
    if isinstance(ws, dict) and isinstance(ws.get("packages"), list):
        return [g for g in ws["packages"] if isinstance(g, str)]
    return []


def _exports_target(val):
    """A package.json `exports` value -> the path string. String as-is; condition object -> import/module/
    default/node/require, else first nested string."""
    if isinstance(val, str):
        return val
    if isinstance(val, dict):
        for k in ("import", "module", "default", "node", "require"):
            if isinstance(val.get(k), str):
                return val[k]
        for v in val.values():
            t = _exports_target(v)
            if t:
                return t
    return None


def _dist_to_src(path):
    """A built package may point exports at dist/, which the git-driven walk excludes. Remap to the src/ twin
    when it exists (defensive — zync's exports point at source, but a built package would not)."""
    norm = path.replace(os.sep, "/")
    if "/dist/" in norm:
        twin = norm.replace("/dist/", "/src/")
        for cand in (twin, re.sub(r"\.m?js$", ".ts", twin)):
            if os.path.isfile(cand):
                return cand
    return path


def _existing_source(path):
    """Mirror resolve()'s on-disk candidate logic: strip .js, try .ts/.tsx/itself/index.ts. -> file or None."""
    base = re.sub(r"\.js$", "", path)
    for cand in (path, base + ".ts", base + ".tsx", base, os.path.join(base, "index.ts")):
        if os.path.isfile(cand):
            return cand
    return None


def build_workspace_aliases(repo_root):
    """pnpm-workspace.yaml (or npm/yarn `workspaces`) + each package.json -> [(specifier, source_file)] aliases
    resolve() consumes. For each workspace package: the bare name '@scope/pkg' -> its exports['.']/module/main
    source entry; each exports subpath '@scope/pkg/x' -> its target. Subpath (longer) specifiers are sorted
    FIRST so resolve()'s exact match picks the most specific. dist/ targets remap to the src/ twin."""
    aliases = []
    globs = _read_pnpm_workspace_globs(repo_root) or _read_npm_workspaces(repo_root)
    for g in globs:
        for pkg_dir in sorted(glob.glob(os.path.join(repo_root, g))):
            pj = os.path.join(pkg_dir, "package.json")
            if not os.path.isfile(pj):
                continue
            try:
                data = json.load(open(pj, encoding="utf-8"))
            except (OSError, ValueError):
                continue
            name = data.get("name")
            if not name:
                continue
            exp = data.get("exports")
            found = []
            if isinstance(exp, dict):
                for key, val in exp.items():
                    t = _exports_target(val)
                    if not t:
                        continue
                    f = _existing_source(_dist_to_src(os.path.normpath(os.path.join(pkg_dir, t))))
                    if not f:
                        continue
                    spec = name if key == "." else name + "/" + (key[2:] if key.startswith("./") else key)
                    found.append((spec, f))
            if not any(s == name for s, _ in found):  # bare-name fallback if exports had no '.'
                cand = (_exports_target(exp["."]) if isinstance(exp, dict) and "." in exp else None) \
                    or data.get("module") or data.get("main") or "src/index.ts"
                f = _existing_source(_dist_to_src(os.path.normpath(os.path.join(pkg_dir, cand))))
                if f:
                    found.append((name, f))
            aliases.extend(found)
    aliases.sort(key=lambda t: -len(t[0]))  # longest specifier first: exact subpath wins before the bare name
    return aliases


def find_repo_root(start):
    """Walk up from `start` to the workspace root (pnpm-workspace.yaml) or git root (.git). Falls back to the
    target's own directory if neither is found (single-file/no-workspace runs degrade to today's behavior)."""
    d = os.path.dirname(os.path.abspath(start))
    while True:
        if os.path.isfile(os.path.join(d, "pnpm-workspace.yaml")) or os.path.isdir(os.path.join(d, ".git")):
            return d
        parent = os.path.dirname(d)
        if parent == d:
            return os.path.dirname(os.path.abspath(start))
        d = parent
```

- [ ] **Step 4: Run the test — verify it passes**

Run: `rtk proxy python3 -m pytest tests/test_gate.py -v`
Expected: both tests PASS.

- [ ] **Step 5: Wire `build_workspace_aliases` into `main()` (hand-passed --alias overrides)**

In `gate.py` `main()`, add two argparse flags (near the other args, ~305):

```python
    ap.add_argument("--no-workspace-alias", action="store_true",
                    help="disable auto pnpm/npm workspace alias discovery (default ON)")
    ap.add_argument("--repo-root", default=None,
                    help="workspace root for alias discovery (default: walk up from target to pnpm-workspace.yaml/.git)")
```

Then replace the alias-building block (~317-320):

```python
    aliases = []
    for al in a.alias:                       # hand-passed FIRST so they OVERRIDE auto-discovered aliases
        pre, _, root = al.partition("=")
        aliases.append((pre, os.path.abspath(root)))
    target = os.path.abspath(a.target)
    if not a.no_workspace_alias:             # auto workspace aliases appended AFTER (resolve() returns first match)
        repo_root = os.path.abspath(a.repo_root) if a.repo_root else find_repo_root(target)
        aliases += build_workspace_aliases(repo_root)
```

(Delete the now-duplicate `target = os.path.abspath(a.target)` line that previously sat at ~324.)

- [ ] **Step 6: Run the full gate + mapper suites (no regression)**

Run: `rtk proxy python3 -m pytest tests/test_gate.py tests/test_mapper.py tests/test_bench.py -v`
Expected: all PASS (workspace discovery is additive; a tree with no pnpm-workspace.yaml gets `[]` aliases → byte-identical to today).

- [ ] **Step 7: Commit**

```bash
command git add orchestrator/gate.py tests/test_gate.py
command git commit -m "#40 Part B1: workspace-aware resolver from pnpm-workspace + package.json exports"
```

---

## Task 4: Part B2 — barrel re-export following to the definition file

**Wave:** 4
**Blocks:** Task 5
**Blocked by:** Task 3

**Files:**
- Modify: `orchestrator/gate.py` (add `resolve_through_barrel` + `_barrel_named_source` above `first_party_value_imports` ~70; wire into `first_party_value_imports` ~91-95)
- Test: `tests/test_gate.py` (add barrel tests)

**Why:** With B1, `@zync/db` resolves to the barrel `src/index.ts` — but the barrel only RE-EXPORTS (`export { tenantQuery } from './queries'`); the body the gate needs is in the definition file. `resolve_through_barrel` follows the re-export chain (cap 3 hops) to the file that actually defines the symbol, so `collect_deps` inlines the real body and `run_oracle_set` scans the real file. Barrel-following is RESOLUTION, not a depth knob — resist a `--barrel-depth` flag (a transparent re-export has exactly one correct target; a depth knob would re-introduce the #36 failure of a real def gated behind a hop count).

- [ ] **Step 1: Write the failing barrel tests**

Add to `tests/test_gate.py`:

```python
def _barrel_tree():
    """importer -> barrel (re-export) -> def. Plus an `as`-rename chain and an `export *` chain."""
    d = tempfile.mkdtemp()
    os.makedirs(os.path.join(d, "pkg"), exist_ok=True)
    open(os.path.join(d, "pkg/barrel.ts"), "w").write(
        "export { buildSession } from './def'\n"
        "export { internalMint as mintToken } from './mint'\n"
        "export * from './starred'\n")
    open(os.path.join(d, "pkg/def.ts"), "w").write("export function buildSession(){ return { enforce2fa:false } }")
    open(os.path.join(d, "pkg/mint.ts"), "w").write("export function internalMint(){ return 't' }")
    open(os.path.join(d, "pkg/starred.ts"), "w").write("export function starHelper(){ return 1 }")
    return d


def test_resolve_through_barrel_named_reexport_reaches_def():
    d = _barrel_tree()
    barrel = os.path.join(d, "pkg/barrel.ts")
    assert gate.resolve_through_barrel(barrel, "buildSession", []) == os.path.join(d, "pkg/def.ts")


def test_resolve_through_barrel_follows_as_rename():
    d = _barrel_tree()
    barrel = os.path.join(d, "pkg/barrel.ts")
    # importer sees `mintToken`; barrel maps it to `internalMint` from ./mint
    assert gate.resolve_through_barrel(barrel, "mintToken", []) == os.path.join(d, "pkg/mint.ts")


def test_resolve_through_barrel_follows_export_star():
    d = _barrel_tree()
    barrel = os.path.join(d, "pkg/barrel.ts")
    assert gate.resolve_through_barrel(barrel, "starHelper", []) == os.path.join(d, "pkg/starred.ts")


def test_resolve_through_barrel_noop_when_symbol_is_local():
    d = _barrel_tree()
    deff = os.path.join(d, "pkg/def.ts")
    assert gate.resolve_through_barrel(deff, "buildSession", []) == deff   # defined here -> unchanged


def test_resolve_through_barrel_local_def_wins_over_export_star():
    """A file that BOTH defines a symbol locally AND has `export * from './sub'`: importing that symbol must
    resolve to THIS file, NOT the star target. Without local-def precedence the gate would inline/scan the
    wrong file and a sink in the local def is a SILENT FALSE-CLEAN (the cardinal failure)."""
    d = tempfile.mkdtemp()
    os.makedirs(os.path.join(d, "pkg"), exist_ok=True)
    open(os.path.join(d, "pkg/utils.ts"), "w").write(
        "export function localThing(){ return 1 }\nexport * from './sub'\n")
    open(os.path.join(d, "pkg/sub.ts"), "w").write("export function other(){ return 2 }")
    utils = os.path.join(d, "pkg/utils.ts")
    assert gate.resolve_through_barrel(utils, "localThing", []) == utils   # local def wins, NOT sub.ts


def test_first_party_value_imports_returns_def_not_barrel():
    d = _barrel_tree()
    importer = os.path.join(d, "pkg/importer.ts")
    open(importer, "w").write("import { buildSession } from './barrel'\nbuildSession()")
    pairs = gate.first_party_value_imports(importer, [])
    files = {f for f, _s in pairs}
    assert os.path.join(d, "pkg/def.ts") in files          # resolved THROUGH the barrel to the def
    assert os.path.join(d, "pkg/barrel.ts") not in files    # the barrel indirection is gone
```

- [ ] **Step 2: Run — verify it fails**

Run: `rtk proxy python3 -m pytest tests/test_gate.py -k barrel -v`
Expected: FAIL — `module 'sg_gate' has no attribute 'resolve_through_barrel'`.

- [ ] **Step 3: Implement `_barrel_named_source` + `resolve_through_barrel`**

In `gate.py`, add the two re-export regexes near the other module-level regexes (~36, after `IMPORT`):

```python
# re-export barrel lines: `export { a, b as c } from 'spec'`  and  `export * from 'spec'` / `export * as ns from 'spec'`
REEXPORT_NAMED = re.compile(r"export\s*\{([^}]*)\}\s*from\s*['\"]([^'\"]+)['\"]")
REEXPORT_STAR = re.compile(r"export\s*\*\s*(?:as\s+\w+\s+)?from\s*['\"]([^'\"]+)['\"]")
```

Then add ABOVE `first_party_value_imports` (~70):

```python
def _barrel_named_source(text, want):
    """If `want` is re-exported by an `export { ... } from 'spec'` line, return (spec, upstream_name) — handling
    `export { internal as want }` (the upstream name in `spec` is `internal`). Else None."""
    for m in REEXPORT_NAMED.finditer(text):
        names_blob, spec = m.group(1), m.group(2)
        for piece in names_blob.split(","):
            piece = piece.strip()
            if not piece:
                continue
            parts = re.split(r"\s+as\s+", piece)
            local, exported = parts[0].strip(), parts[-1].strip()
            if exported == want:
                return spec, local
    return None


def _defines_local(text, want):
    """True if `want` is locally DEFINED-and-exported in this file (NOT via a re-export `from`). A local
    definition WINS over an `export * from ...` aggregator: `resolve_through_barrel` runs on EVERY first-party
    import, so a file that BOTH defines `want` AND carries `export *` would otherwise mis-resolve `want` to the
    star target — inlining/scanning the wrong file while a sink in the local def goes unscanned = a SILENT
    FALSE-CLEAN (the cardinal failure). Local def must short-circuit before the star branch is consulted."""
    w = re.escape(want)
    # `export default function want` / `export (async) function|const|let|var|class|enum want`
    if re.search(r"\bexport\s+(?:default\s+)?(?:async\s+)?(?:function|const|let|var|class|enum)\s+" + w + r"\b", text):
        return True
    # local `export { want }` / `export { internal as want }` WITHOUT a trailing `from` (a re-export has `from`)
    for m in re.finditer(r"\bexport\s*\{([^}]*)\}(?!\s*from)", text):
        for piece in m.group(1).split(","):
            parts = re.split(r"\s+as\s+", piece.strip())
            if parts[-1].strip() == want:
                return True
    return False


def resolve_through_barrel(file, symbol, aliases, max_hops=3):
    """Follow re-export barrels from `file` to the file that DEFINES `symbol`. Returns the definition file, or
    `file` unchanged when the symbol is locally defined or cannot be followed within max_hops. Logs to stderr on
    cap hit. `export *` lines are followed breadth-first (the symbol may arrive via any). Barrel-following is
    RESOLUTION (one correct target per transparent re-export), NOT a tunable depth — the cap is a cycle/pathology
    backstop only. A re-export from a bare package (node_modules) is out of scope -> bundle the barrel as-is."""
    seen = set()
    frontier = [(file, symbol, 0)]
    while frontier:
        f, want, hop = frontier.pop(0)
        if f in seen:
            continue
        seen.add(f)
        try:
            text = open(f, encoding="utf-8", errors="replace").read()
        except OSError:
            continue
        named = _barrel_named_source(text, want)
        if named:
            spec, upstream = named
            nxt = resolve(spec, os.path.dirname(f), aliases)
            if not nxt:
                return f  # re-exported from a bare package (out of scope)
            if hop + 1 >= max_hops:
                print(f"[barrel] hop cap {max_hops} reached resolving `{symbol}` from {os.path.relpath(file)}",
                      file=sys.stderr)
                return nxt
            frontier.insert(0, (nxt, upstream, hop + 1))  # follow the precise edge depth-first
            continue
        if _defines_local(text, want):
            return f  # locally defined here -> WINS over any `export *` aggregator (prevents a false-clean)
        stars = REEXPORT_STAR.findall(text)
        if not stars:
            return f  # not re-exported and no star-aggregator -> treat this as the def site
        if hop + 1 >= max_hops:
            print(f"[barrel] hop cap {max_hops} reached (export*) resolving `{symbol}` from {os.path.relpath(file)}",
                  file=sys.stderr)
            return f
        for spec in stars:
            nxt = resolve(spec, os.path.dirname(f), aliases)
            if nxt and nxt not in seen:
                frontier.append((nxt, want, hop + 1))  # export* targets breadth-first
    return file
```

- [ ] **Step 4: Wire into `first_party_value_imports`**

In `first_party_value_imports`, replace the per-symbol append loop (~94-95):

```python
        for s in syms:
            deff = resolve_through_barrel(f, s, aliases)  # follow a re-export barrel to the symbol's def file
            (crit_first if CRITICAL.search(s) else rest).append((deff, s))
```

Update the docstring's first line to: `parse imports -> [(definition_file, symbol)] for ALL first-party VALUE imports (barrel re-exports followed to the def; type-only lines skipped).`

- [ ] **Step 5: Run the barrel tests — verify they pass**

Run: `rtk proxy python3 -m pytest tests/test_gate.py -v`
Expected: all `test_resolve_through_barrel_*` + `test_first_party_value_imports_returns_def_not_barrel` PASS, plus the B1 tests still PASS.

- [ ] **Step 6: Run the full suite (no regression)**

Run: `rtk proxy python3 -m pytest tests/ -v`
Expected: all PASS (a non-barrel import: `_barrel_named_source` returns None, no `export *` → `resolve_through_barrel` returns the file unchanged = today's behavior).

- [ ] **Step 7: Commit**

```bash
command git add orchestrator/gate.py tests/test_gate.py
command git commit -m "#40 Part B2: follow barrel re-exports to the definition file"
```

---

## Task 5: Part B deterministic plumbing gate — def body in bundle + oracle reaches resolved def (#42)

**Wave:** 5
**Blocks:** Task 6
**Blocked by:** Task 4

**Files:**
- Test: `tests/test_gate.py` (add deterministic plumbing tests — NO bun, NO LLM)

**Why (the #42 hard gate):** Barrel-following relocates the in-scope file from barrel → def. That relocation is exactly the #42 failure mode (relocating WHERE one leg reads silently shrinks ANOTHER leg's reach). The LLM bundle and the oracle set both derive from `first_party_value_imports` → `collect_deps`, so resolution flows to BOTH automatically — but "automatic" must be PROVEN, not assumed. These tests assert (a) `build_bundle` contains the DEFINITION body (not the barrel line) and (b) the file list `[target] + [d[0] for d in deps]` that `main()` passes to `run_oracle_set` CONTAINS the resolved def file. Deterministic: no `bun`, no `claude`.

- [ ] **Step 1: Write the plumbing tests (failing until the wiring from Tasks 3-4 is in place — they exercise it end to end)**

Add to `tests/test_gate.py`:

```python
def _xfile_barrel_tree():
    """importer -> @zync/db barrel -> def body carrying an oracle-class marker, via a real pnpm workspace so
    build_workspace_aliases + resolve_through_barrel BOTH fire (the full Part B path)."""
    d = tempfile.mkdtemp()
    open(os.path.join(d, "pnpm-workspace.yaml"), "w").write("packages:\n  - 'packages/*'\n  - 'apps/*'\n")
    db = os.path.join(d, "packages/db/src")
    os.makedirs(db, exist_ok=True)
    open(os.path.join(d, "packages/db/package.json"), "w").write(json.dumps({
        "name": "@zync/db", "exports": {".": "./src/index.ts"}}))
    open(os.path.join(db, "index.ts"), "w").write("export { buildSessionPayload } from './session'\n")  # barrel
    open(os.path.join(db, "session.ts"), "w").write(
        "// DEF_BODY_MARKER\nexport function buildSessionPayload(a){ return { enforce_2fa: a.enforce2fa ?? false } }\n")
    app = os.path.join(d, "apps/api/src/routes")
    os.makedirs(app, exist_ok=True)
    importer = os.path.join(app, "refresh.ts")
    open(importer, "w").write("import { buildSessionPayload } from '@zync/db'\nbuildSessionPayload({})\n")
    return d, importer


def test_bundle_and_oracle_set_reach_barrel_resolved_def():
    d, importer = _xfile_barrel_tree()
    aliases = gate.build_workspace_aliases(d)
    deps, dropped = gate.collect_deps(importer, aliases, 1, 60)
    dep_files = [f for f, _s, _imp in deps]
    def_file = os.path.join(d, "packages/db/src/session.ts")
    barrel = os.path.join(d, "packages/db/src/index.ts")
    assert def_file in dep_files            # collect_deps reached THROUGH the barrel to the def
    assert barrel not in dep_files          # the barrel indirection is not what gets inlined
    # (a) LLM bundle carries the DEF BODY, not the barrel re-export line
    bundle = gate.build_bundle(importer, deps)
    assert "DEF_BODY_MARKER" in bundle
    assert "enforce_2fa: a.enforce2fa ?? false" in bundle
    # (b) #42: the file list main() hands to run_oracle_set CONTAINS the resolved def file
    oracle_set_files = [importer] + dep_files
    assert def_file in oracle_set_files     # oracle leg follows the resolution -> no silent false-clean
```

- [ ] **Step 2: Run it**

Run: `rtk proxy python3 -m pytest tests/test_gate.py::test_bundle_and_oracle_set_reach_barrel_resolved_def -v`
Expected: PASS (Tasks 3+4 already wired the path; this test is the explicit #42 proof). If it FAILS, the resolution did not flow to `collect_deps` — fix the wiring in Task 4 Step 4, do not weaken the test.

- [ ] **Step 3: Commit**

```bash
command git add tests/test_gate.py
command git commit -m "#40 Part B plumbing gate: def body in bundle + oracle set reaches resolved def (#42)"
```

---

## Task 6: Part B measurement — resolution coverage on real zync + barrel cell

**Wave:** 6
**Blocks:** —
**Blocked by:** Task 5

**Files:**
- Create: `docs/validation/2026-06-18-partB-resolution-coverage.md`
- Create: `domains/security/corpus/S1-barrel-2fa-on-refresh/{vuln.ts,barrel.ts,imported-builder.ts,safe.ts,canonical.json}`

**Why:** The headline metric is RESOLUTION COVERAGE (static, 0-LLM, reproducible): first-party `@zync/*` value imports resolving to a real file BEFORE (0) vs AFTER. This is an ENABLER, not a catch — the value chain stays explicit: `coverage ↑ → oracle/LLM reaches more first-party sinks → catches (demonstrated downstream by the #24 recall sweep)`. Do NOT present the coverage delta as a recall result. The barrel cell confirms the already-known S1 catch SURVIVES barrel indirection (a plumbing/resolution proof), NOT a new recall win (Shape-B scarcity n=1/85 — building a synthetic for a recall claim is forbidden).

- [ ] **Step 1: Measure resolution coverage on the real zync tree (gated on checkout)**

If `/home/user/Projects/zync.is` is checked out, write a short throwaway measurement using the gate's own functions (load `gate.py` by path; build aliases; for every tracked `.ts` under `apps/`, parse first-party `@zync/*` imports and count resolved-to-real-file vs total, per-package). Run:

```bash
rtk proxy python3 - <<'PY'
import importlib.util, os, subprocess, re
ROOT="/home/user/Projects/security-gate"; REPO="/home/user/Projects/zync.is"
def load(n,p):
    s=importlib.util.spec_from_file_location(n,p); m=importlib.util.module_from_spec(s); s.loader.exec_module(m); return m
g=load("g",os.path.join(ROOT,"orchestrator","gate.py"))
aliases=g.build_workspace_aliases(REPO)
files=subprocess.run(["git","-C",REPO,"ls-files","apps/**/*.ts"],capture_output=True,text=True).stdout.split("\n")
tot={}; res={}
for rel in files:
    if not rel.strip(): continue
    p=os.path.join(REPO,rel); src=open(p,encoding="utf-8",errors="replace").read()
    for m in g.IMPORT.finditer(src):
        spec=m.group(2)
        if not spec.startswith("@zync/"): continue
        pkg=spec.split("/")[1]; tot[pkg]=tot.get(pkg,0)+1
        if g.resolve(spec, os.path.dirname(p), aliases): res[pkg]=res.get(pkg,0)+1
for pkg in sorted(tot): print(f"@zync/{pkg}: {res.get(pkg,0)}/{tot[pkg]}")
print("TOTAL:", sum(res.values()), "/", sum(tot.values()))
PY
```

The BEFORE number is 0 for all `@zync/*` (no aliases existed) — confirm by re-running with `aliases=[]`. Record per-package resolved/total AFTER and the BEFORE 0. If zync is not checked out, record the gate ("not measured — zync.is not checked out") and rely on the deterministic Task 5 test + the synthetic-workspace tests as the wiring proof.

- [ ] **Step 2: Create the barrel-wrapped S1 cell (resolution proof, NOT a recall claim)**

Reconstruct the real S1 canonical body with RAW git (never routed `git show`):

Run: `command git --no-pager -C /home/user/Projects/zync.is show ead618d~1:apps/zync-api/src/routes/auth/refresh.ts` (and the builder file) to get the faithful pre-fix bodies. Then create:

- `domains/security/corpus/S1-barrel-2fa-on-refresh/imported-builder.ts` — the `buildSessionPayload` body with `enforce_2fa: args.enforce2fa ?? false` (the insecure default), copied faithfully from the real builder.
- `domains/security/corpus/S1-barrel-2fa-on-refresh/barrel.ts` — `export { buildSessionPayload } from './imported-builder'` (the indirection layer; this is the ONLY new element vs the existing `S1-xfile-2fa-on-refresh` cell).
- `domains/security/corpus/S1-barrel-2fa-on-refresh/vuln.ts` — `refresh.ts` importing `buildSessionPayload` from `./barrel` and calling it WITHOUT `enforce2fa`.
- `domains/security/corpus/S1-barrel-2fa-on-refresh/safe.ts` — the post-fix variant passing `enforce2fa` through (the discriminator).
- `domains/security/corpus/S1-barrel-2fa-on-refresh/canonical.json`:

```json
{"id":"S1-barrel-2fa-on-refresh","domain":"security","class":"S1","band":2,"shape":"B-imported-insecure-default-via-barrel","file":"vuln.ts","line":1,"fix_sha":"ead618d","canonical_symbol":"buildSessionPayload enforce2fa omission","requires_resolution":true,"resolution":"barrel re-export (vuln.ts -> barrel.ts -> imported-builder.ts)","purpose":"RESOLUTION proof: confirms the known S1-xfile catch survives a barrel indirection layer; NOT a new recall claim (Shape-B scarcity n=1/85, building a synthetic for recall is forbidden)","why":"same canonical as S1-xfile-2fa-on-refresh, with one barrel layer added between caller and builder so resolve_through_barrel must follow it for the builder body to reach the review bundle"}
```

- [ ] **Step 3: Verify the cell resolves end-to-end via --dry-run (deterministic, no LLM)**

Run: `rtk proxy python3 orchestrator/gate.py domains/security/corpus/S1-barrel-2fa-on-refresh/vuln.ts --dry-run --no-workspace-alias`
Expected: the `[dep]` lines list `imported-builder.ts` (resolved THROUGH `barrel.ts`), confirming the builder body would be inlined. (Relative imports need no workspace alias; `--no-workspace-alias` keeps the cell self-contained.)

- [ ] **Step 4: (Optional, gated on cost) confirm the known catch survives barrel indirection**

ONLY if running the LLM leg: refresh creds first — `rm -rf /tmp/sg_cfg && mkdir -p /tmp/sg_cfg && cp ~/.claude/.credentials.json /tmp/sg_cfg/.credentials.json && chmod 600 /tmp/sg_cfg/.credentials.json`. Then `rtk proxy python3 orchestrator/gate.py domains/security/corpus/S1-barrel-2fa-on-refresh/vuln.ts --k 3 --config-dir /tmp/sg_cfg --no-workspace-alias`. Expected: the `buildSessionPayload enforce2fa omission` finding appears (known S1 catch survives the barrel). Record as a RESOLUTION confirmation, NOT a recall win.

- [ ] **Step 5: Write the coverage doc**

Write `docs/validation/2026-06-18-partB-resolution-coverage.md` (audience: AI coding agents first): per-package `@zync/*` resolution coverage BEFORE (0) vs AFTER (the measured numbers, or the honest "not measured — gate" note); the value-chain statement (coverage = enabler; catch evidence = downstream #24 sweep; never present coverage as recall); the barrel cell result (def body reaches the bundle; oracle reaches the def file per the Task 5 test; known catch survives if Step 4 was run). State the open measurement this phase OPENS: cross-file PRECISION at n≥3.

- [ ] **Step 6: Commit**

```bash
command git add docs/validation/2026-06-18-partB-resolution-coverage.md domains/security/corpus/S1-barrel-2fa-on-refresh/
command git commit -m "#40 Part B measured: @zync/* resolution coverage 0->N, barrel cell survives indirection"
```

---

## NOT covered in v1 (honest scope — deferred no-ops, logged-not-silent)

- **tsconfig `paths` non-package aliases (D4 REJECTED).** Measured-redundant with `build_workspace_aliases` on every repo in evidence (zync's per-package `paths` map to the same source files workspace discovery computes). A `paths`-only internal alias (e.g. `@zync/db/internal` not in the `exports` map) degrades to `None` — no regression, acceptable. Documented no-op until a measured repo needs it.
- **2-hop+ transitive package→package barrels beyond the cap.** `resolve_through_barrel` caps at 3 hops and LOGS to stderr on cap hit — never silently dropped. Raising the cap is deliberate, not a default.
- **npm/yarn `workspaces`.** Read best-effort via the same globs (`_read_npm_workspaces`); only pnpm-workspace is MEASURED. Marked best-effort until a real npm/yarn repo exercises it.
- **Cross-file PRECISION at n≥3.** This is the open measurement this phase OPENS (per the #40 charter): more resolved imports = more inlined bodies = more surface for paraphrased-duplicate findings. The precision guard is `#17a semantic_merge` (already wired); the broad precision sweep is its own follow.

---

## Self-Review

**1. Spec coverage:** Part A file-routed enumeration by location → Task 1 (mapper) + Task 2 (measure). KIND_SIGNALS-intact / branch-enumeration → Task 1 Steps 4-5. File-routed denominator location + kind_coverage_by_volume meaning → Task 1 Steps 4,8. Part A acceptance (multideal edge-function==2, http-file-route measure-not-assert + inspect drops, new export-default test) → Task 1 Step 1, Task 2 Steps 1-3. Part B1 workspace aliases (exports priority, dist→src, longest-first, --alias override) → Task 3. Part B2 barrel-follow (cap 3, log, export* BFS, as-rename) → Task 4. #42 oracle-reach hard gate → Task 5. Coverage-not-fabricated-bug validation → Task 6 Steps 1,2,5. Defers (tsconfig paths, 2-hop, npm/yarn, precision n≥3) → NOT-covered section. ALL spec requirements mapped.

**2. Placeholder scan:** No TBD/TODO/"handle edge cases"/"similar to". Every code step has complete code. Task 6 Step 1 is a real runnable measurement script, gated honestly on checkout.

**3. Type/name consistency:** `build_workspace_aliases`, `resolve_through_barrel`, `_barrel_named_source`, `_defines_local`, `_file_routed_kind`, `find_repo_root`, `_existing_source`, `_dist_to_src`, `_exports_target`, `_read_pnpm_workspace_globs`, `_read_npm_workspaces` used consistently across tasks. `resolve()` returns a file path; `first_party_value_imports` returns `[(file, symbol)]`; `collect_deps` returns `(deps=[(file,symbol,importer)], dropped)` — Task 5 unpacks `(f, _s, _imp)` correctly. `file_routed_recall` new fields (`enumerated`, `content_signal_hits`, `within_kind_recall`, `retired_signal_recall`) consistent between Task 1 Steps 6,7 and the bench note Step 8. `test_bench`'s `within_kind_recall["http-file-route"]["within_kind_recall"]==1.0` still holds (now location-based).

**4. Wave plan:** Every task has Wave/Blocks/Blocked-by. Table matches. No two tasks share a wave (each wave = 1 task), so zero intra-wave file overlap by construction. Tasks 3,4,5 all touch `gate.py`/`test_gate.py` → correctly placed in SEPARATE sequential waves. Part B (Waves 3-6) blocked on Part A MEASURED (Wave 2), enforcing pilot-before-fanout.
