fix(watcher): never walk into raw/rejected/ — brain_reject (closes #81)
Adds brain_reject (RejectNote + MCP tool) and fixes the watcher to skip raw/rejected/, preventing declined notes from being silently re-ingested and republished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Mathias <mthbqv@gmail.com>
This commit was merged in pull request #133.
This commit is contained in:
@@ -176,15 +176,20 @@ func TestDeriveSource(t *testing.T) {
|
||||
func TestProcessDir_SkipsSubdirs(t *testing.T) {
|
||||
brainDir := setupBrainDir(t)
|
||||
|
||||
// Create processed/ and failed/ subdirs with files inside.
|
||||
for _, sub := range []string{"processed/2026-04-22", "failed"} {
|
||||
// Create processed/, failed/, and rejected/ subdirs with files inside.
|
||||
for _, sub := range []string{"processed/2026-04-22", "failed", "rejected"} {
|
||||
require.NoError(t, os.MkdirAll(filepath.Join(brainDir, "raw", sub), 0o755))
|
||||
}
|
||||
|
||||
processedFile := filepath.Join(brainDir, "raw", "processed", "2026-04-22", "old-file.md")
|
||||
failedFile := filepath.Join(brainDir, "raw", "failed", "broken-file.md")
|
||||
// hyperguild#81/#133: a human already declined this note via brain_reject.
|
||||
// If the watcher walks into rejected/, it re-ingests and publishes it to
|
||||
// the wiki — the exact opposite of the human's decision.
|
||||
rejectedFile := filepath.Join(brainDir, "raw", "rejected", "declined-file.md")
|
||||
require.NoError(t, os.WriteFile(processedFile, []byte("old"), 0o644))
|
||||
require.NoError(t, os.WriteFile(failedFile, []byte("broken"), 0o644))
|
||||
require.NoError(t, os.WriteFile(rejectedFile, []byte("---\nrejected_at: 2026-09-23T00:00:00Z\n---\ndeclined"), 0o644))
|
||||
|
||||
// Also place a valid file in raw/ root that should be processed.
|
||||
validFile := filepath.Join(brainDir, "raw", "valid.md")
|
||||
@@ -223,11 +228,13 @@ func TestProcessDir_SkipsSubdirs(t *testing.T) {
|
||||
// Complete should have been called exactly once (for valid.md, not for files in subdirs).
|
||||
assert.Len(t, processedSources, 1, "only the file in raw/ root should be processed")
|
||||
|
||||
// Files in processed/ and failed/ must remain untouched.
|
||||
// Files in processed/, failed/, and rejected/ must remain untouched.
|
||||
_, err := os.Stat(processedFile)
|
||||
assert.NoError(t, err, "processed subdir file should be untouched")
|
||||
_, err = os.Stat(failedFile)
|
||||
assert.NoError(t, err, "failed subdir file should be untouched")
|
||||
_, err = os.Stat(rejectedFile)
|
||||
assert.NoError(t, err, "rejected subdir file should be untouched, never re-ingested")
|
||||
}
|
||||
|
||||
// TestProcessDir_SkipsTunnelCandidateFiles guards against hyperguild#88:
|
||||
|
||||
Reference in New Issue
Block a user