Skip to content

Commit 708c688

Browse files
Fix auto indexer resolution to always mean PHP (#77)
Root cause: HealthChecker and IndexerResolver probed for the Pagefind binary when indexer was set to 'auto', reporting binary as active. This contradicts the design rule that auto always means PHP. The binary pipeline requires explicit 'indexer: binary' configuration. Fixes: HealthChecker.check() now reads the configured indexer setting instead of probing binary availability. IndexerResolver.resolve() returns 'php' for auto without binary probe (dead code but corrected for consistency). Tests updated to assert the correct auto=php behavior.
1 parent 3600779 commit 708c688

5 files changed

Lines changed: 73 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ This project uses [Semantic Versioning](https://semver.org/). Major versions are
66

77
## [Unreleased]
88

9-
_No changes yet._
9+
### Fixed
10+
- **`auto` indexer now always means PHP on all code paths.** `HealthChecker::check()` now reads the configured `indexer` setting instead of probing binary availability when reporting `indexer_active` — it previously reported `binary` whenever the Pagefind binary was present on disk, even when the setting was `auto` or `php`. `IndexerResolver::resolve()` likewise returns `php` for `auto` without probing the binary. The binary pipeline requires explicit `indexer: binary` configuration.
1011

1112
## [1.0.0-rc1] - 2026-05-11
1213

src/Health/HealthChecker.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ public function check(): array
5454
$status = 'degraded';
5555
}
5656

57-
$indexerActive = $binaryStatus['available'] ? 'binary' : 'php';
58-
$upgradeMessage = $binaryStatus['available']
59-
? null
60-
: 'Pagefind binary not found. Using PHP indexer (slower, 14 Snowball languages vs 33+). '
61-
. 'For faster indexing: npm install -g pagefind';
57+
$configuredIndexer = $this->config->indexer ?? 'auto';
58+
$indexerActive = ($configuredIndexer === 'binary' && $binaryStatus['available']) ? 'binary' : 'php';
59+
$upgradeMessage = ($configuredIndexer === 'binary' && !$binaryStatus['available'])
60+
? 'Pagefind binary not found. Set indexer to "php" or install Pagefind: npm install -g pagefind'
61+
: null;
6262

6363
return [
6464
'status' => $status,
@@ -68,7 +68,7 @@ public function check(): array
6868
'wasm_available' => false,
6969
'index_exists' => $indexExists,
7070
'indexer_active' => $indexerActive,
71-
'indexer_upgrade_available' => !$binaryStatus['available'],
71+
'indexer_upgrade_available' => ($configuredIndexer === 'binary' && !$binaryStatus['available']),
7272
'indexer_upgrade_message' => $upgradeMessage,
7373
'pagefind' => [
7474
'available' => $binaryStatus['available'],

src/Index/IndexerResolver.php

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010
/**
1111
* Resolves which indexer backend to use and emits notice-level log messages.
1212
*
13-
* Encapsulates auto-detection and fallback logic so every adapter emits
14-
* the same structured messages. Adapters call resolve() and act on the
15-
* returned string ('php' or 'binary'). All logging is handled here.
13+
* Encapsulates indexer selection logic so every adapter emits the same
14+
* structured messages. Adapters call resolve() and act on the returned
15+
* string ('php' or 'binary'). All logging is handled here.
16+
*
17+
* Design rule: 'auto' always means PHP. Binary pipeline requires explicit
18+
* 'indexer: binary' configuration. If binary is unavailable when 'binary'
19+
* is configured, falls back to PHP with a log notice.
1620
*
1721
* Log messages:
1822
* - [scolta] Using PHP indexer.
@@ -54,16 +58,9 @@ public function resolve(string $effectiveIndexer): string
5458
return 'php';
5559
}
5660

57-
// 'auto' (or any unrecognised value): probe binary, fall back to PHP.
58-
$path = $this->binary->resolve();
59-
if ($path !== null) {
60-
$this->logger->notice(
61-
'[scolta] Using binary indexer (auto-detected): {binary}.',
62-
['binary' => $path],
63-
);
64-
return 'binary';
65-
}
66-
$this->logger->notice('[scolta] Using PHP indexer (auto: binary not available).');
61+
// 'auto' (or any unrecognised value): always PHP.
62+
// Binary pipeline requires explicit 'indexer: binary' configuration.
63+
$this->logger->notice('[scolta] Using PHP indexer.');
6764
return 'php';
6865
}
6966
}

tests/Health/HealthCheckerTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,45 @@ public function testIndexCheckVerifiesPagefindJs(): void
156156
$this->assertTrue($result2['index_exists']);
157157
}
158158

159+
// -------------------------------------------------------------------
160+
// indexer_active reflects config, not binary availability
161+
// -------------------------------------------------------------------
162+
163+
public function testIndexerActiveIsPhpWhenConfigIsAuto(): void
164+
{
165+
$config = ScoltaConfig::fromArray(['ai_api_key' => 'sk-test', 'indexer' => 'auto']);
166+
$checker = new HealthChecker($config, $this->tempDir, null, null);
167+
168+
$result = $checker->check();
169+
170+
$this->assertSame('php', $result['indexer_active']);
171+
}
172+
173+
public function testIndexerActiveIsPhpWhenConfigIsPhp(): void
174+
{
175+
$config = ScoltaConfig::fromArray(['ai_api_key' => 'sk-test', 'indexer' => 'php']);
176+
$checker = new HealthChecker($config, $this->tempDir, null, null);
177+
178+
$result = $checker->check();
179+
180+
$this->assertSame('php', $result['indexer_active']);
181+
}
182+
183+
public function testIndexerActiveIsBinaryWhenConfigIsBinaryAndBinaryAvailable(): void
184+
{
185+
// Create a fake binary so PagefindBinary reports available.
186+
$tempBin = $this->tempDir . '/pagefind';
187+
file_put_contents($tempBin, "#!/bin/sh\necho 'pagefind 1.5.0'");
188+
chmod($tempBin, 0755);
189+
190+
$config = ScoltaConfig::fromArray(['ai_api_key' => 'sk-test', 'indexer' => 'binary']);
191+
$checker = new HealthChecker($config, $this->tempDir, $tempBin, null);
192+
193+
$result = $checker->check();
194+
195+
$this->assertSame('binary', $result['indexer_active']);
196+
}
197+
159198
// -------------------------------------------------------------------
160199
// Helpers
161200
// -------------------------------------------------------------------

tests/Index/IndexerResolverTest.php

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,31 @@ public function testBinaryModeWithMissingBinaryLogsFallback(): void
116116
}
117117

118118
// -------------------------------------------------------------------
119-
// 'auto' mode — binary available
119+
// 'auto' mode — always PHP regardless of binary availability
120120
// -------------------------------------------------------------------
121121

122-
public function testAutoModeWithAvailableBinaryReturnsBinary(): void
122+
public function testAutoModeReturnsPhp(): void
123+
{
124+
$logger = new IndexerResolverLogger();
125+
$resolver = new IndexerResolver(new PagefindBinary(), $logger);
126+
127+
$result = $resolver->resolve('auto');
128+
129+
$this->assertSame('php', $result);
130+
}
131+
132+
public function testAutoModeWithAvailableBinaryStillReturnsPhp(): void
123133
{
124134
$logger = new IndexerResolverLogger();
125135
$binary = new PagefindBinary(configuredPath: $this->fakeBinary);
126136
$resolver = new IndexerResolver($binary, $logger);
127137

128138
$result = $resolver->resolve('auto');
129139

130-
$this->assertSame('binary', $result);
140+
$this->assertSame('php', $result);
131141
}
132142

133-
public function testAutoModeWithAvailableBinaryLogsBinaryIndexer(): void
143+
public function testAutoModeLogsUsingPhpIndexer(): void
134144
{
135145
$logger = new IndexerResolverLogger();
136146
$binary = new PagefindBinary(configuredPath: $this->fakeBinary);
@@ -140,15 +150,10 @@ public function testAutoModeWithAvailableBinaryLogsBinaryIndexer(): void
140150

141151
$this->assertCount(1, $logger->records);
142152
$this->assertSame('notice', $logger->records[0]['level']);
143-
$this->assertStringContainsString('Using binary indexer', $logger->records[0]['message']);
144-
$this->assertStringContainsString('auto-detected', $logger->records[0]['message']);
153+
$this->assertStringContainsString('Using PHP indexer', $logger->records[0]['message']);
145154
}
146155

147-
// -------------------------------------------------------------------
148-
// 'auto' mode — binary not available → fallback
149-
// -------------------------------------------------------------------
150-
151-
public function testAutoModeWithoutBinaryFallsBackToPhp(): void
156+
public function testAutoModeWithoutBinaryReturnsPhp(): void
152157
{
153158
$logger = new IndexerResolverLogger();
154159
$resolver = new IndexerResolver(new UnavailablePagefindBinary(), $logger);
@@ -158,18 +163,6 @@ public function testAutoModeWithoutBinaryFallsBackToPhp(): void
158163
$this->assertSame('php', $result);
159164
}
160165

161-
public function testAutoModeWithoutBinaryLogsPhpIndexer(): void
162-
{
163-
$logger = new IndexerResolverLogger();
164-
$resolver = new IndexerResolver(new UnavailablePagefindBinary(), $logger);
165-
166-
$resolver->resolve('auto');
167-
168-
$this->assertCount(1, $logger->records);
169-
$this->assertSame('notice', $logger->records[0]['level']);
170-
$this->assertStringContainsString('Using PHP indexer', $logger->records[0]['message']);
171-
}
172-
173166
// -------------------------------------------------------------------
174167
// IndexBuildOrchestrator emits "Using PHP indexer" notice
175168
// -------------------------------------------------------------------

0 commit comments

Comments
 (0)