fix(pipeline,classification): read the brain through brainfs (#157, slice 6) #176

Merged
mathias merged 3 commits from fix/pipeline-root-157 into main 2026-10-05 18:54:42 +00:00
Owner

Refs #157 (slice 6). risk/high: control code, adversarial review required.

Problem

These read with os.ReadFile / os.ReadDir, so a symlinked file's content reached the place listed, and a FIFO hung the ingest or startup:

  • readSourcePage, loadSchema → the LLM prompt (1.6M leaks in the swap race)
  • reviseOrCreate, injectSourceRefs, BackfillRefs → the pages the pipeline writes
  • classification.Load → the I1 sovereignty levels. A FIFO hung startup.

Change

  • pipeline:
    • readSourcePage, loadSchema, reviseOrCreate and injectSourceRefs read via readBrainFile (brainfs ReadRegular).
    • reviseOrCreate(brainDir, page) reads page.Path. A missing page is created; a non-regular page is an error.
    • BackfillRefs lists with ReadDirRegular and reads with ReadRegular.
  • classification.Load:
    • reads through brainfs; a symlinked or special file is a hard error, as a malformed file is
    • an absent file or brain dir still gives the default config
    • At startup a load error exits the process. The startup symlink tripwire removes symlinks first, so a planted link does not crash-loop the pod. A FIFO is not a symlink, though, so it would now exit instead of hang.

Tests

All have outside and in-brain targets and positive controls. All four pipeline tests are red against the old pipeline code, and the classification test is red (hang) against the old Load.

  • TestReadSourcePageAndSchemaRefuseSymlinksAndSurviveSwapRaces
  • TestReviseOrCreateRefusesASymlinkedExistingPage
  • TestInjectSourceRefsDoesNotReadASymlinkedPage
  • TestBackfillRefsSkipsSymlinkedSourcesAndPages
  • TestBackfillRefsDoesNotWriteARefFromASourceSwappedInBehindASymlink
  • TestLoadRefusesASymlinkedOrFIFOClassificationFile

A first draft used bare [[slug]] links, which the pipeline ignores (it only follows [[slug|title]]). Its positive controls failed and caught it.

Flips (red)

  • readBrainFile reverted to os.ReadFile (3 tests)
  • the BackfillRefs source read via os.ReadFile (race test)
  • classification.Load via os.ReadFile

Not covered

  • Pipeline writes (os.WriteFile of pages, BackfillRefs writes): #158.
  • provenance.ApplyFile: a read-modify-write that needs brainfs.WriteRegular from #170, so it moves to #158 after #170.
  • Intermediate in-brain dir redirects: #167.

🤖 Generated with Claude Code


Created via git-mcp on behalf of @mathias

Refs #157 (slice 6). risk/high: control code, adversarial review required. ## Problem These read with `os.ReadFile` / `os.ReadDir`, so a symlinked file's content reached the place listed, and a FIFO hung the ingest or startup: - **`readSourcePage`, `loadSchema`** → the **LLM prompt** (1.6M leaks in the swap race) - **`reviseOrCreate`, `injectSourceRefs`, `BackfillRefs`** → the **pages the pipeline writes** - **`classification.Load`** → the **I1 sovereignty levels**. A FIFO hung startup. ## Change - **pipeline:** - `readSourcePage`, `loadSchema`, `reviseOrCreate` and `injectSourceRefs` read via `readBrainFile` (brainfs `ReadRegular`). - `reviseOrCreate(brainDir, page)` reads `page.Path`. A missing page is created; a non-regular page is an error. - `BackfillRefs` lists with `ReadDirRegular` and reads with `ReadRegular`. - **classification.Load:** - reads through brainfs; a symlinked or special file is a hard error, as a malformed file is - an absent file or brain dir still gives the default config - At startup a load error exits the process. The startup symlink tripwire removes symlinks first, so a planted link does not crash-loop the pod. A FIFO is not a symlink, though, so it would now exit instead of hang. ## Tests All have outside **and in-brain** targets and positive controls. All four pipeline tests are red against the old pipeline code, and the classification test is red (hang) against the old Load. - `TestReadSourcePageAndSchemaRefuseSymlinksAndSurviveSwapRaces` - `TestReviseOrCreateRefusesASymlinkedExistingPage` - `TestInjectSourceRefsDoesNotReadASymlinkedPage` - `TestBackfillRefsSkipsSymlinkedSourcesAndPages` - `TestBackfillRefsDoesNotWriteARefFromASourceSwappedInBehindASymlink` - `TestLoadRefusesASymlinkedOrFIFOClassificationFile` A first draft used bare `[[slug]]` links, which the pipeline ignores (it only follows `[[slug|title]]`). Its positive controls failed and caught it. ## Flips (red) - `readBrainFile` reverted to `os.ReadFile` (3 tests) - the BackfillRefs source read via `os.ReadFile` (race test) - `classification.Load` via `os.ReadFile` ## Not covered - **Pipeline writes** (`os.WriteFile` of pages, BackfillRefs writes): #158. - **`provenance.ApplyFile`:** a read-modify-write that needs `brainfs.WriteRegular` from #170, so it moves to #158 after #170. - **Intermediate in-brain dir redirects:** #167. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- _Created via git-mcp on behalf of @mathias_
mathias added the risk/high label 2026-10-05 05:14:08 +00:00
mathias reviewed 2026-10-05 05:21:36 +00:00
mathias left a comment
Author
Owner

Gatekeeper review of PR #176 (slice 6: pipeline readers and classification.Load through brainfs; head 70df6db): BLOCKED. Not merged, verdict only.

Blocking

1. ingestion/internal/pipeline/backfill.go:82: the BackfillRefs concept-page read has no test. Reverting it to os.ReadFile keeps the suite green.

  • Flip: bfs.ReadRegular(relPath) → os.ReadFile(filepath.Join(brainDir, relPath)). Every test passes (rc=0).
  • Why: the page half of TestBackfillRefsSkipsSymlinkedSourcesAndPages places a static symlinked concept page. wiki.LoadInventory (ReadDirRegular) never lists that page, so findInInventory drops the slug before the changed line runs. The assertion holds because of slice 4's inventory filter, not this read. The test name is true of BackfillRefs end to end, but nothing in the suite pins the line this PR changed.
  • The line is reachable. A page that is regular when the inventory is listed and is swapped for an in-brain symlink before the read gets there. I ran a probe in a scratch copy that does exactly that: one source links a concept page, and the swapper alternates the page between a regular file and a relative symlink to another brain file carrying the sentinel. The concept page is opened with O_NOFOLLOW after each BackfillRefs run.
    • PR head, 3 runs × 3 s: 0 sentinel copies in the page.
    • With the flip, 3 of 3 runs: sentinel copied into the concept page, i.e. other-brain content rewritten into a wiki page.
    • Writing that probe as a per-caller test closes this. Slice 4 round 1 blocked on the same pattern (a caller-level Lstat bypass stayed green), and #171 tracks it for slices 1 to 3. A new slice should not add another instance.

Non-blocking (record; not this PR's to fix)

  • #158, write-through under race, observed by execution. The same probe on PR head overwrote the in-brain symlink target about 5,000 times in 3 s. BackfillRefs reads the regular page, the swapper puts a symlink in its place, and then os.WriteFile(dest) follows the symlink. buildAndWrite (MkdirAll + WriteFile) and wiki.AppendLog have the same shape. This PR does not make it worse, and reviseOrCreate refusing a static symlink now stops the static final-link write-through that main had. A target outside the brain would get the same write. Please make sure #158 includes BackfillRefs explicitly.
  • Abort, not skip. reviseOrCreate on a symlinked existing page returns an error, which aborts buildAndWrite partway: earlier pages are written, and the index rebuild and log append are skipped. That is better than writing through the link, but the watcher moves the file to failed/. Consider skip-with-warning in #158.
  • (c) classification.Load fail-hard is correct. An absent file falls back to defaults, so fail-open on a refused file would drop explicit tags, some of which may be stricter than the default. I checked these by execution: a no-writer FIFO, a FIFO with a writer, a directory and a dangling link each return "not a regular file" promptly with no hang; a missing brainDir returns defaults. A symlinked file cannot reach line 537, because startupSymlinkCheck exits first. A FIFO passes the tripwire (symlinkguard only reports symlinks). On main it hung startup forever in open(2). Now it is a fast, logged os.Exit(1) that names the file. That is still a crash-loop for whoever can create special files in the pod volume, but Syncthing does not sync FIFOs, so it needs local write access. Optional: have symlinkguard report special files too, so the tripwire message names them.
  • TestInjectSourceRefsDoesNotReadASymlinkedPage uses a hand-built inventory that includes the symlink. Production LoadInventory would filter it, so in production that read is reachable only by a race. The unit test is still valid, and its name does not overclaim.
  • Nit: the brainfs import sits inside the stdlib import group in 3 files. Lint passes.

Checked and held (by execution)

  • (a) Prompt inputs. No os.ReadFile/ReadDir/Open/Walk remains in internal/pipeline, internal/classification or internal/wiki apart from the AppendLog write. The prompt is built from LoadInventory (slice 4), loadSchema and readSourcePage, and the latter two are pinned by flips. The content comes from callers that went through ResolveIngestPath/ReadIngestFile/extract.OpenRegular in earlier slices. I did not re-attack those here.
  • (b) LLM-controlled paths. Dry-run RunRaw over 80 type × title combinations (dot-dot segments, slashes, backslashes, absolute paths, U+2215, fullwidth dots, NUL, upper case) and 3 hostile source values. Every produced path was wiki/<type>/<slug>.md with exactly 2 slashes, so none could escape. Two things enforce this: validPageType (^[a-z][a-z0-9-]*$), and wiki.Slug, which keeps only letters, digits and hyphens. Resolve substitutes an inventory slug, which is a stem of a regular file name and so cannot contain /. A file named ...md gives slug .., but the path becomes wiki/<t>/...md, which is a file name, not a traversal. So I found no write traversal through filepath.Join(brainDir, page.Path).
  • Flips that went red: readSourcePage, loadSchema, reviseOrCreate, injectSourceRefs, the BackfillRefs source read (swap test), the BackfillRefs list and read together (static test), classification read to os.ReadFile, classification fail-open on any error, and brainfs SameFile removal.
  • (d) Rule 9. Apart from finding 1, each name matches what its assertions check.
  • go test -race -count=5 on pipeline and classification: green. CI=1 task check: exit 0 (lint, race tests, gitleaks), and the worktree stayed clean. CI run 9323 (ci.yml, pull_request) succeeded at 70df6db: green, and green covers none of finding 1.

Not checked

Hard links and in-brain intermediate dir redirects (accepted, #167). The write path beyond what the probe observed (#158). The callers that produce content (earlier slices). Behaviour on a non-Linux FS. The live deploy.

The PR is labelled risk/high, so the merge is Mathias's call even after a PASS.

Gatekeeper review of PR #176 (slice 6: pipeline readers and classification.Load through brainfs; head 70df6db): **BLOCKED**. Not merged, verdict only. ## Blocking **1. `ingestion/internal/pipeline/backfill.go:82`: the BackfillRefs concept-page read has no test. Reverting it to `os.ReadFile` keeps the suite green.** - Flip: `bfs.ReadRegular(relPath)` → `os.ReadFile(filepath.Join(brainDir, relPath))`. Every test passes (rc=0). - Why: the page half of `TestBackfillRefsSkipsSymlinkedSourcesAndPages` places a *static* symlinked concept page. `wiki.LoadInventory` (ReadDirRegular) never lists that page, so `findInInventory` drops the slug before the changed line runs. The assertion holds because of slice 4's inventory filter, not this read. The test name is true of BackfillRefs end to end, but nothing in the suite pins the line this PR changed. - The line is reachable. A page that is regular when the inventory is listed and is swapped for an in-brain symlink before the read gets there. I ran a probe in a scratch copy that does exactly that: one source links a concept page, and the swapper alternates the page between a regular file and a relative symlink to another brain file carrying the sentinel. The concept page is opened with O_NOFOLLOW after each BackfillRefs run. - PR head, 3 runs × 3 s: **0** sentinel copies in the page. - With the flip, 3 of 3 runs: sentinel copied into the concept page, i.e. other-brain content rewritten into a wiki page. - Writing that probe as a per-caller test closes this. Slice 4 round 1 blocked on the same pattern (a caller-level Lstat bypass stayed green), and #171 tracks it for slices 1 to 3. A new slice should not add another instance. ## Non-blocking (record; not this PR's to fix) - **#158, write-through under race, observed by execution.** The same probe on PR head overwrote the in-brain symlink *target* about 5,000 times in 3 s. BackfillRefs reads the regular page, the swapper puts a symlink in its place, and then `os.WriteFile(dest)` follows the symlink. `buildAndWrite` (`MkdirAll` + `WriteFile`) and `wiki.AppendLog` have the same shape. This PR does not make it worse, and `reviseOrCreate` refusing a static symlink now stops the static final-link write-through that main had. A target outside the brain would get the same write. Please make sure #158 includes BackfillRefs explicitly. - **Abort, not skip.** `reviseOrCreate` on a symlinked existing page returns an error, which aborts `buildAndWrite` partway: earlier pages are written, and the index rebuild and log append are skipped. That is better than writing through the link, but the watcher moves the file to `failed/`. Consider skip-with-warning in #158. - **(c) classification.Load fail-hard is correct.** An absent file falls back to defaults, so fail-open on a refused file would drop explicit tags, some of which may be stricter than the default. I checked these by execution: a no-writer FIFO, a FIFO with a writer, a directory and a dangling link each return "not a regular file" promptly with no hang; a missing brainDir returns defaults. A symlinked file cannot reach line 537, because `startupSymlinkCheck` exits first. A **FIFO** passes the tripwire (symlinkguard only reports symlinks). On main it hung startup forever in `open(2)`. Now it is a fast, logged `os.Exit(1)` that names the file. That is still a crash-loop for whoever can create special files in the pod volume, but Syncthing does not sync FIFOs, so it needs local write access. Optional: have symlinkguard report special files too, so the tripwire message names them. - `TestInjectSourceRefsDoesNotReadASymlinkedPage` uses a hand-built inventory that includes the symlink. Production `LoadInventory` would filter it, so in production that read is reachable only by a race. The unit test is still valid, and its name does not overclaim. - Nit: the `brainfs` import sits inside the stdlib import group in 3 files. Lint passes. ## Checked and held (by execution) - **(a) Prompt inputs.** No `os.ReadFile`/`ReadDir`/`Open`/`Walk` remains in `internal/pipeline`, `internal/classification` or `internal/wiki` apart from the AppendLog write. The prompt is built from `LoadInventory` (slice 4), `loadSchema` and `readSourcePage`, and the latter two are pinned by flips. The content comes from callers that went through `ResolveIngestPath`/`ReadIngestFile`/`extract.OpenRegular` in earlier slices. I did not re-attack those here. - **(b) LLM-controlled paths.** Dry-run `RunRaw` over 80 type × title combinations (dot-dot segments, slashes, backslashes, absolute paths, U+2215, fullwidth dots, NUL, upper case) and 3 hostile `source` values. Every produced path was `wiki/<type>/<slug>.md` with exactly 2 slashes, so none could escape. Two things enforce this: `validPageType` (`^[a-z][a-z0-9-]*$`), and `wiki.Slug`, which keeps only letters, digits and hyphens. `Resolve` substitutes an inventory slug, which is a stem of a regular file name and so cannot contain `/`. A file named `...md` gives slug `..`, but the path becomes `wiki/<t>/...md`, which is a file name, not a traversal. So I found no write traversal through `filepath.Join(brainDir, page.Path)`. - Flips that went red: readSourcePage, loadSchema, reviseOrCreate, injectSourceRefs, the BackfillRefs source read (swap test), the BackfillRefs list and read together (static test), classification read to os.ReadFile, classification fail-open on any error, and brainfs SameFile removal. - **(d) Rule 9.** Apart from finding 1, each name matches what its assertions check. - `go test -race -count=5` on pipeline and classification: green. `CI=1 task check`: exit 0 (lint, race tests, gitleaks), and the worktree stayed clean. CI run 9323 (ci.yml, pull_request) succeeded at 70df6db: **green, and green covers none of finding 1.** ## Not checked Hard links and in-brain intermediate dir redirects (accepted, #167). The write path beyond what the probe observed (#158). The callers that produce `content` (earlier slices). Behaviour on a non-Linux FS. The live deploy. The PR is labelled `risk/high`, so the merge is Mathias's call even after a PASS.
mathias reviewed 2026-10-05 07:31:19 +00:00
mathias left a comment
Author
Owner

Gatekeeper round 2 on PR #176 (slice 6, head 3cfe345): BLOCKED. Not merged, verdict only. One small fix is needed.

Blocking

1. ingestion/internal/pipeline/root_test.go:165: the new test's positive control does not check what its message says (rule 9). As a result the test stays green when BackfillRefs reads or writes nothing.

require.Contains(t, read(), "zqinside", "positive control: the regular page gets the ref")

zqinside is already in the page before BackfillRefs runs, so this assertion holds whether or not a ref was added. I ran TestBackfillRefsDoesNotCopyAPageSwappedInBehindASymlink alone with each of these flips in a scratch copy:

flip in backfill.go new test
page read → os.ReadFile red (3 of 3; e.g. 4145 leaks in 87k iterations)
page read → always fs.ErrNotExist (no page is ever read) green
return 0, nil right after LoadInventory (BackfillRefs does nothing) green

Other backfill tests do catch the last two, so the suite as a whole goes red. The problem is this test alone. A refusal test whose positive control cannot tell "refused the swapped link" from "never read anything" passes for the wrong reason, and the message makes it look as if it proves more.

Fix (verified): assert on the ref instead, e.g. require.Contains(t, read(), "[[s|S]]", ...). With that change the test is green on head, red when no page is read, and still red under the os.ReadFile flip.

Verified, held

  • Round 1's blocker is closed. The page-read flip now turns the new test red.
  • Non-blocking items are recorded: #158 has a comment naming the BackfillRefs/buildAndWrite/AppendLog write-through, and #179 (symlinkguard ignores FIFOs) is open.
  • go test -race -count=5 on pipeline and classification passes. CI=1 task check exits 0, and the worktree is clean.
  • CI run 9347 succeeded at 3cfe345. It is green, but it does not cover finding 1.
  • The round-1 checks were not re-run: the diff since 70df6db only adds this test.

Not checked

Same as round 1: #167 residuals, write paths (#158), upstream content callers, live deploy. The PR is risk/high, so the merge is Mathias's call.

Gatekeeper round 2 on PR #176 (slice 6, head 3cfe345): **BLOCKED**. Not merged, verdict only. One small fix is needed. ## Blocking **1. `ingestion/internal/pipeline/root_test.go:165`: the new test's positive control does not check what its message says (rule 9). As a result the test stays green when BackfillRefs reads or writes nothing.** ```go require.Contains(t, read(), "zqinside", "positive control: the regular page gets the ref") ``` `zqinside` is already in the page before BackfillRefs runs, so this assertion holds whether or not a ref was added. I ran `TestBackfillRefsDoesNotCopyAPageSwappedInBehindASymlink` alone with each of these flips in a scratch copy: | flip in backfill.go | new test | |---|---| | page read → `os.ReadFile` | **red** (3 of 3; e.g. 4145 leaks in 87k iterations) | | page read → always `fs.ErrNotExist` (no page is ever read) | **green** | | return `0, nil` right after LoadInventory (BackfillRefs does nothing) | **green** | Other backfill tests do catch the last two, so the suite as a whole goes red. The problem is this test alone. A refusal test whose positive control cannot tell "refused the swapped link" from "never read anything" passes for the wrong reason, and the message makes it look as if it proves more. **Fix (verified):** assert on the ref instead, e.g. `require.Contains(t, read(), "[[s|S]]", ...)`. With that change the test is green on head, red when no page is read, and still red under the `os.ReadFile` flip. ## Verified, held - Round 1's blocker is closed. The page-read flip now turns the new test red. - Non-blocking items are recorded: #158 has a comment naming the BackfillRefs/buildAndWrite/AppendLog write-through, and #179 (symlinkguard ignores FIFOs) is open. - `go test -race -count=5` on pipeline and classification passes. `CI=1 task check` exits 0, and the worktree is clean. - CI run 9347 succeeded at 3cfe345. It is green, but it does not cover finding 1. - The round-1 checks were not re-run: the diff since 70df6db only adds this test. ## Not checked Same as round 1: #167 residuals, write paths (#158), upstream content callers, live deploy. The PR is `risk/high`, so the merge is Mathias's call.
mathias added 3 commits 2026-10-05 18:48:25 +00:00
The ingest pipeline read wiki/sources/<slug>.md and schema.md (both go
into the LLM prompt), the pages it revises, and the pages it adds
source refs to, with os.ReadFile; BackfillRefs listed wiki/sources with
os.ReadDir. A symlinked file's content reached the prompt and the
written pages (1.6M leaks in the race), and a FIFO hung the ingest.
classification.Load (the I1 sovereignty levels) read
classification.yaml the same way and hung startup on a FIFO.

- pipeline: readSourcePage, loadSchema, reviseOrCreate, injectSourceRefs
  read through readBrainFile (brainfs ReadRegular); reviseOrCreate takes
  the brain dir and reads page.Path, a missing page is still created and
  a non-regular one is an error. BackfillRefs lists with ReadDirRegular
  and reads with ReadRegular.
- classification.Load: read through brainfs; a symlinked or special
  classification.yaml is a hard error (as a malformed one is); an absent
  file or brain dir still yields the default config.

Tests use in-brain targets and the [[slug|title]] link form the pipeline
actually follows (bare [[slug]] links are ignored by it, which made a
first draft of the backfill test vacuous).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 on PR #176: reverting the BackfillRefs concept-page read
to os.ReadFile left every test green. The static symlinked page never
reaches that read, because LoadInventory does not list it; the read is
reachable only when a page listed as regular is swapped for a symlink
before it is read. New test does that against an in-brain target and
reads the page back with O_NOFOLLOW; red under the flip (2/2), green
3/3 on head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test(pipeline): the page-swap test's positive control asserts the source ref (#157)
CI / Lint / Test / Vet (pull_request) Successful in 1m0s
CI / Mirror to GitHub (pull_request) Skipped
b8ea201bd3
Review round 2 on PR #176: the control checked for text that was in the
page before BackfillRefs ran, so the test stayed green when no page was
read at all. It now asserts the [[s|S]] ref BackfillRefs adds; red when
the page read always fails, still red when the read follows the link.
Branch rebased onto main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mathias force-pushed fix/pipeline-root-157 from 3cfe345415 to b8ea201bd3 2026-10-05 18:48:25 +00:00 Compare
mathias reviewed 2026-10-05 18:52:20 +00:00
mathias left a comment
Author
Owner

Gatekeeper round 3 on PR #176 (slice 6, head b8ea201): PASS. Not merged, verdict only. The PR is risk/high, so the merge is Mathias's call.

Rebase scope (verified)

  • The branch sits on current main (febab3e). git range-diff shows the two round-2 commits are patch-identical (=) after the rebase. The only new commit is b8ea201, which changes one line in pipeline/root_test.go.
  • git diff origin/main...b8ea201 touches only the same 6 files as before: classification/{classification.go,root_test.go} and pipeline/{backfill.go,pipeline.go,refs.go,root_test.go}. The rebase brought nothing else in.
  • Main's own changes to brainfs since the PR's original base (ReadDirDirs, WriteRegular, and the #177 floors in AssertNoLeakFrom) are not in this PR's diff. The floors now apply to this PR's swap tests, which require a swap to have happened and an inside read to have returned. All of them pass.

Round-2 blocker closed (by execution)

TestBackfillRefsDoesNotCopyAPageSwappedInBehindASymlink, run alone against flips in a scratch copy:

flip in backfill.go round 2 round 3
page read → os.ReadFile red red (4173 leaks in 83k iterations)
page read → always fs.ErrNotExist green red (positive control, line 165)
return right after LoadInventory green red (positive control)

Round-1 flips, re-run on the rebased tree, all red

readSourcePage, loadSchema, reviseOrCreate, injectSourceRefs, the BackfillRefs source read, classification read → os.ReadFile, and brainfs SameFile removal (which turns 3 swap tests red, including the new one).

Gates

  • go test -race -count=5 on pipeline and classification: green.
  • CI=1 task check at b8ea201: exit 0, 0 FAIL lines, worktree clean.
  • CI run 9444 (pull_request) succeeded at b8ea201. Gitea reports the PR as mergeable.

Carried forward, not blocking

Write-through on BackfillRefs, buildAndWrite and AppendLog, and skip-vs-abort, are tracked in #158. The FIFO classification.yaml crash-loop is tracked in #179. Hard links and intermediate redirects are tracked in #167.

Not checked

The upstream content callers (earlier slices), write paths beyond the round-1 probe, and the live deploy and post-merge smoke test.

Gatekeeper round 3 on PR #176 (slice 6, head b8ea201): **PASS**. Not merged, verdict only. The PR is `risk/high`, so the merge is Mathias's call. ## Rebase scope (verified) - The branch sits on current main (febab3e). `git range-diff` shows the two round-2 commits are patch-identical (`=`) after the rebase. The only new commit is b8ea201, which changes one line in `pipeline/root_test.go`. - `git diff origin/main...b8ea201` touches only the same 6 files as before: `classification/{classification.go,root_test.go}` and `pipeline/{backfill.go,pipeline.go,refs.go,root_test.go}`. The rebase brought nothing else in. - Main's own changes to brainfs since the PR's original base (ReadDirDirs, WriteRegular, and the #177 floors in `AssertNoLeakFrom`) are not in this PR's diff. The floors now apply to this PR's swap tests, which require a swap to have happened and an inside read to have returned. All of them pass. ## Round-2 blocker closed (by execution) `TestBackfillRefsDoesNotCopyAPageSwappedInBehindASymlink`, run alone against flips in a scratch copy: | flip in backfill.go | round 2 | round 3 | |---|---|---| | page read → `os.ReadFile` | red | **red** (4173 leaks in 83k iterations) | | page read → always `fs.ErrNotExist` | green | **red** (positive control, line 165) | | return right after LoadInventory | green | **red** (positive control) | ## Round-1 flips, re-run on the rebased tree, all red readSourcePage, loadSchema, reviseOrCreate, injectSourceRefs, the BackfillRefs source read, classification read → os.ReadFile, and brainfs SameFile removal (which turns 3 swap tests red, including the new one). ## Gates - `go test -race -count=5` on pipeline and classification: green. - `CI=1 task check` at b8ea201: exit 0, 0 FAIL lines, worktree clean. - CI run 9444 (pull_request) succeeded at b8ea201. Gitea reports the PR as mergeable. ## Carried forward, not blocking Write-through on BackfillRefs, buildAndWrite and AppendLog, and skip-vs-abort, are tracked in #158. The FIFO `classification.yaml` crash-loop is tracked in #179. Hard links and intermediate redirects are tracked in #167. ## Not checked The upstream `content` callers (earlier slices), write paths beyond the round-1 probe, and the live deploy and post-merge smoke test.
mathias merged commit eedb110be5 into main 2026-10-05 18:54:42 +00:00
Sign in to join this conversation.