patch 15
This commit is contained in:
216
src/Config/GovernanceConfig.php
Normal file
216
src/Config/GovernanceConfig.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Config;
|
||||
|
||||
final class GovernanceConfig
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
*/
|
||||
public function __construct(private readonly array $config = [])
|
||||
{
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedShortModelTokens(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_short_model_tokens');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedMeasurementValues(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_measurement_values');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedTechnicalPromptKeywords(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_technical_prompt_keywords');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionTechnicalPriorityRequiredMarkers(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.technical_priority_required_markers');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedAccessoryPromptKeywords(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_accessory_prompt_keywords');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedSearchRepairSpecificityTerms(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_search_repair_specificity_terms');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionProtectedRetrievalReagentWords(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.protected_retrieval_reagent_words');
|
||||
}
|
||||
|
||||
/** @return array<string, string[]> */
|
||||
public function getRegressionProtectedRetrievalDeviceWordGroups(): array
|
||||
{
|
||||
$value = $this->requiredValue('regression_baseline.protected_retrieval_device_word_groups');
|
||||
if (!is_array($value)) {
|
||||
throw $this->invalid('regression_baseline.protected_retrieval_device_word_groups', 'must be a map of string lists');
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($value as $key => $item) {
|
||||
if (is_string($key) && is_array($item)) {
|
||||
$normalizedKey = trim($key);
|
||||
$terms = $this->normalizeStringList($item);
|
||||
if ($normalizedKey !== '' && $terms !== []) {
|
||||
$out[$normalizedKey] = $terms;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Backwards-compatible reader for the temporary p15/p15b list-of-groups shape.
|
||||
if (is_array($item)) {
|
||||
$groupKey = isset($item['key']) && is_scalar($item['key']) ? trim((string) $item['key']) : '';
|
||||
$terms = $this->normalizeStringList($item['terms'] ?? []);
|
||||
if ($groupKey !== '' && $terms !== []) {
|
||||
$out[$groupKey] = $terms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($out === []) {
|
||||
throw $this->invalid('regression_baseline.protected_retrieval_device_word_groups', 'must contain at least one valid group');
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function getRegressionShopPromptOriginalQuery(): string
|
||||
{
|
||||
return $this->requiredString('regression_baseline.shop_prompt_regression_original_query');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionShopPromptRequiredOutputInstructionMarkers(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.shop_prompt_required_output_instruction_markers');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionShopQueryMetaGuardTerms(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.shop_query_meta_guard_terms');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getRegressionShopQueryContextFallbackFilterTerms(): array
|
||||
{
|
||||
return $this->requiredStringList('regression_baseline.shop_query_context_fallback_filter_terms');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getVocabularyProtectedShortModelTokens(): array
|
||||
{
|
||||
return $this->requiredStringList('vocabulary.protected_short_model_tokens');
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getLanguageProtectedStopwordTerms(): array
|
||||
{
|
||||
return $this->requiredStringList('language.protected_stopword_terms');
|
||||
}
|
||||
|
||||
private function requiredString(string $path): string
|
||||
{
|
||||
$value = $this->requiredValue($path);
|
||||
if (!is_scalar($value)) {
|
||||
throw $this->invalid($path, 'must be a scalar string');
|
||||
}
|
||||
|
||||
$value = trim((string) $value);
|
||||
if ($value === '') {
|
||||
throw $this->invalid($path, 'must not be empty');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function requiredStringList(string $path): array
|
||||
{
|
||||
return $this->nonEmptyStringList($path, $this->requiredValue($path));
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function nonEmptyStringList(string $path, mixed $value): array
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
throw $this->invalid($path, 'must be a string list');
|
||||
}
|
||||
|
||||
$out = $this->normalizeStringList($value);
|
||||
if ($out === []) {
|
||||
throw $this->invalid($path, 'must contain at least one value');
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function normalizeStringList(mixed $value): array
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($value as $item) {
|
||||
if (!is_scalar($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = trim((string) $item);
|
||||
if ($item !== '' && !in_array($item, $out, true)) {
|
||||
$out[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function requiredValue(string $path): mixed
|
||||
{
|
||||
$value = $this->config;
|
||||
foreach (explode('.', $path) as $segment) {
|
||||
if (!is_array($value) || !array_key_exists($segment, $value)) {
|
||||
throw $this->missing($path);
|
||||
}
|
||||
|
||||
$value = $value[$segment];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function missing(string $path): \InvalidArgumentException
|
||||
{
|
||||
return new \InvalidArgumentException(sprintf('RetrieX governance config "%s" is missing.', $path));
|
||||
}
|
||||
|
||||
private function invalid(string $path, string $reason): \InvalidArgumentException
|
||||
{
|
||||
return new \InvalidArgumentException(sprintf('RetrieX governance config "%s" %s.', $path, $reason));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user