# v0.3 Acceptance — Linux Corpus (strncpy removal)
This is the v0.3 corpus-benchmark acceptance run for the Linux row in
`docs/v0.3-contract.md`'s "Corpus benchmarks and budgets" table. It reruns the
scenario documented in `docs/experiments/linux-strncpy-removal.md` against the
installed v0.3 CLI, adding the required-evidence checks the contract demands:
(a) the current tree confirms `strncpy` the core kernel API is absent, and (b)
a deleted-API report on this shallow clone is explicitly historical — surfaced
as a truthful `base_revision_unavailable` failure, never a guessed diff.
## Subject
- Repo: `torvalds/linux`
- Pinned submodule commit: `1a3746ccbb0a97bed3c06ccde6b880013b1dddc1`
- Subject: `Merge tag 'strncpy-removal-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux`
- Machine: local macOS (darwin), `ochna` installed globally via `make install`
(`ochna --version` reports `0.2.0`; the binary exposes all v0.3 subcommands:
`doctor`, `unresolved`, `tests-for`, `impact`, `diff`)
- All work happened in disposable temp directories outside the repo. The live
submodule at `clones/linux` was never `cd`-ed into or mutated; only `git
archive` (read-only) and `cp -r` (read-only copy) touched it.
## Part A — current-tree absence check
Archived the pinned tree into a fresh directory and indexed it standalone
(no `.git`, tree-only):
```bash
mkdir -p /tmp/ochna-accept-linux-tree
```
- Archive + extract: `26.9s` wall clock.
- `ochna init`: `1:56.57` wall clock (`253.31s` user, `14.59s` system, 229% CPU).
- Index result: `65221` files, `1403920` nodes, `1645608` resolved edges,
`2355864` unresolved references (from `4477237` raw calls).
`ochna status --json`:
```json
{
"action": "none",
"counts": {"edges": 1645608, "files": 65221, "nodes": 1403920},
"db_present": true,
"freshness": "unknown",
"ok": true,
"schema": {"expected": 6, "found": 6, "match": true}
}
```
(`git`/`head_sha` fields are `N/A`/`null` here because this is a bare archive
extract with no `.git` — expected and consistent with the tree-only mode used
in the prior experiment.)
`ochna search strncpy --json` returned 16 matches. Critically, **none of them
is the removed core kernel API**: the only exact-name `strncpy` hit is
`tools/include/nolibc/string.h::strncpy`, a distinct tool-only nolibc helper
(matches the prior experiment's finding). The rest are genuinely different
APIs that must not be confused with the removed one:
`strncpy_from_user` (multiple arch/lib definitions), `strncpy_from_bpfptr`,
`strncpy_from_sockptr`, `strncpy_chunk_from_user`,
`strncpy_from_user_nofault`, `strncpy_from_kernel_nofault`, `safe_strncpy`,
`acpi_ut_safe_strncpy`, `do_strncpy_from_user`, `raw_strncpy_from_user`
(Rust), `strnlen_user`, `libbpf_strlcpy`. No graph confusion between
`strncpy` and these distinct, differently-named APIs was observed.
Direct file checks confirmed the core API's absence at its former locations:
```bash
ochna node --file include/linux/fortify-string.h --symbols-only --json | jq -r '.[].name' | grep -i strncpy # (empty)
```
All three greps returned nothing. As a sanity check that file parsing itself
still works, `lib/string.c` still yields 36 other `str*` symbols
(`strcpy`, `strcat`, `strcmp`, `sized_strscpy`, ...) — the file is indexed
correctly, `strncpy` is simply gone from it.
`ochna unresolved --in lib/string.c --json` returned 13 unresolved references
(macro/helper calls like `WARN_ON_ONCE`, `IS_ENABLED`, `load_unaligned_zeropad`),
none referencing `strncpy` as a phantom call target.
**Verdict: PASS.** The current tree confirms `strncpy` the core kernel API is
absent, and the graph does not conflate it with the distinct
`strncpy_from_user`/`strncpy_from_kernel_nofault`/nolibc/helper APIs.
Temp directory removed: `rm -rf /tmp/ochna-accept-linux-tree`.
## Part B — historical diff honesty check
Full copy including `.git`, so `ochna diff` has real Git history available
to query (even though the pin is a shallow checkout with no parent commit
locally):
```bash
mkdir -p /tmp/ochna-accept-linux-full
cp -r .../clones/linux/. /tmp/ochna-accept-linux-full/
```
- Copy: `45.6s` wall clock (`0.81s` user, `32.97s` system — mostly I/O syscall
overhead scanning file metadata), resulting in `1.8G` on disk.
- The submodule's `.git` is a gitlink file pointing at the superproject's
`.git/modules/clones/linux`, which a plain `cp -r` does not follow. To get a
real, independent Git history in the copy (required for `ochna diff` to
even attempt a revision lookup) the actual `.git/modules/clones/linux`
directory was also copied read-only into the temp copy's `.git`, and its
`core.worktree` setting was repointed from the relative
`../../../../clones/linux` to the absolute `/tmp/ochna-accept-linux-full`
so all subsequent Git operations resolve inside the temp copy only. This
copy and single config edit happened entirely under `/tmp` and never wrote
to `.git/modules/clones/linux` or `clones/linux` in the source repo.
- Confirmed before indexing:
- `git rev-parse HEAD` → `1a3746ccbb0a97bed3c06ccde6b880013b1dddc1` (matches
the pin).
- `git rev-parse --is-shallow-repository` → `true`.
`cd /tmp/ochna-accept-linux-full && ochna init`:
- `1:54.56` wall clock (`255.75s` user, `13.72s` system, 235% CPU).
- Same index shape as Part A: `65221` files, `1645608` resolved edges from
`4477237` raw calls, `2355864` unresolved references.
- This run correctly picked up real Git metadata: `Commit SHA:
1a3746ccbb0a97bed3c06ccde6b880013b1dddc1`, matching commit message/date,
`Git Status: dirty` (the pre-existing tracked-file modifications carried
over from the source submodule, as expected of a straight copy).
`ochna diff --base HEAD^ --head HEAD --json` (exit code `1`):
```json
{
"command": "diff",
"contract_version": "0.3",
"data": {
"base": null,
"edges": [],
"files": [],
"head": null,
"historical_snapshot": null,
"newly_unresolved_callers": [],
"symbols": [],
"unmapped_hunks": []
},
"next_action": "provide a base revision",
"ok": false,
"truncated": false,
"warnings": [
{
"code": "base_revision_unavailable",
"message": "Base revision \"HEAD^\" is unavailable locally (git rev-parse --verify --end-of-options HEAD^: fatal: Needed a single revision). Fetch it before requesting historical deltas; shallow clones may need git fetch --deepen."
}
]
}
```
**Verdict: PASS — truthful, structured failure.** `ok` is `false`, the
warning code is exactly the contract-specified `base_revision_unavailable`,
`next_action` is the prescribed `"provide a base revision"`, and every
collection (`files`, `symbols`, `edges`, `newly_unresolved_callers`,
`unmapped_hunks`) is an empty array rather than a fabricated or guessed diff.
`historical_snapshot` is `null`, confirming no temporary historical index was
silently substituted or left behind. Ochna correctly declines to answer
rather than inventing a removed-`strncpy` diff from name/prefix matching.
Temp directory removed: `rm -rf /tmp/ochna-accept-linux-full` (1.8G reclaimed).
## Acceptance summary
| Current tree confirms `strncpy` absence as a real API | PASS — absent from `lib/string.c`, `include/linux/string.h`, `include/linux/fortify-string.h`; distinct APIs (`strncpy_from_user`, `strncpy_from_kernel_nofault`, nolibc `strncpy`, `safe_strncpy`, etc.) correctly not conflated with it |
| Deleted-API report is explicitly historical, never guessed | PASS — shallow-clone `ochna diff --base HEAD^ --head HEAD` returns `ok: false`, `base_revision_unavailable`, `next_action: "provide a base revision"`, all collections empty, no fabricated diff |
Both required-evidence claims from the contract's Linux corpus row hold on
the installed v0.3 CLI. No file inside `clones/linux` or the superproject's
`.git/modules/clones/linux` was modified; all indexing and diff work ran
against disposable `/tmp` copies that were removed after use.