# API Reference

This file is generated from JSDoc comments in `src/*.js`.
Run `npm run docs:api` after changing public exports or their JSDoc.

## Worked example: programmatic scoring

The package currently publishes these modules for CLI reuse, but deep imports should be treated as unstable until an explicit `exports` map is introduced.

Use `scoreText` directly when you want patina's score envelope inside another Node.js tool. This example injects a mock `callLLM` so the snippet is deterministic; replace it with the default HTTP caller plus provider credentials in production.

```js
import { getRepoRoot, loadConfig } from 'patina-cli/src/config.js';
import { loadPatterns } from 'patina-cli/src/loader.js';
import { scoreText } from 'patina-cli/src/scoring.js';

const config = loadConfig();
config.language = 'en';

const patterns = loadPatterns(getRepoRoot(), config.language);
const text = 'Coffee has emerged as a pivotal cultural phenomenon.';

const result = await scoreText({
  text,
  config,
  patterns,
  model: 'deterministic-example',
  callLLM: async () => JSON.stringify({
    categories: {
      content: { detected: 1, sum: 1, max: 18, score: 5.6, weighted: 1.7 },
    },
    overall: 24,
    interpretation: 'mostly human',
  }),
});

console.log(result.overall); // 24 unless deterministic shadow scoring reconciles upward
console.log(result.interpretation); // mostly human
```

## Generated reference

<!-- Generated by scripts/generate-api-docs.mjs using jsdoc-to-markdown. Do not edit by hand. -->

## Classes

<a name="HttpError"></a>
### HttpError

Error raised for non-2xx HTTP responses from an LLM provider.

**Kind**: global class

#### Constructor parameters

| Param | Type | Description |
| --- | --- | --- |
| status | `number` | HTTP status code returned by the provider. |
| body | `string` | Response body text, truncated in the message. |
| retryAfter | `string` \| `null` | Raw Retry-After response header, if present. |

**Example**

```js
throw new HttpError(429, 'rate limit', '2');
```

<a name="PatinaCliError"></a>
### PatinaCliError

Structured CLI error with separate what/why/action fields and exit code.

**Kind**: global class

#### Constructor parameters

| Param | Type | Description |
| --- | --- | --- |
| options | `object` | Error fields. |
| options.what | `string` | Short failure headline. |
| options.why | `string` | Explanation of the failure. |
| options.action | `string` | Suggested user action. |
| [options.exitCode=1] | `number` | Process exit code. |

**Example**

```js
throw new PatinaCliError({ what: 'missing input', why: 'No file was provided', action: 'Pass a file path.' });
```

## Constants

<dl>
<dt><a href="#DEFAULT_TEMPERATURE">DEFAULT_TEMPERATURE</a> : <code>number</code></dt>
<dd><p>Default sampling temperature for OpenAI-compatible chat completion calls.</p>
</dd>
<dt><a href="#HTTP_KEY_ENV_VARS">HTTP_KEY_ENV_VARS</a> : <code>Array.&lt;string&gt;</code></dt>
<dd><p>Environment variable names checked for HTTP provider authentication.</p>
</dd>
<dt><a href="#DEFAULT_HTTP_KEY_ENV_VARS">DEFAULT_HTTP_KEY_ENV_VARS</a> : <code>Array.&lt;string&gt;</code></dt>
<dd><p>Default key lookup order for the OpenAI-compatible HTTP provider.</p>
</dd>
<dt><a href="#CACHE_SCHEMA_VERSION">CACHE_SCHEMA_VERSION</a> : <code>number</code></dt>
<dd><p>On-disk response cache schema version.</p>
</dd>
<dt><a href="#DEFAULT_CACHE_TTL_SECONDS">DEFAULT_CACHE_TTL_SECONDS</a> : <code>number</code></dt>
<dd><p>Default response cache time-to-live: one day.</p>
</dd>
<dt><a href="#defaultLogger">defaultLogger</a> : <code>Object</code></dt>
<dd><p>Default stderr logger used by simple callers.</p>
</dd>
<dt><a href="#MANIFEST_SCHEMA_VERSION">MANIFEST_SCHEMA_VERSION</a> : <code>string</code></dt>
<dd><p>Current reproducibility manifest schema version.</p>
</dd>
<dt><a href="#PROVIDERS">PROVIDERS</a> : <code>Record.&lt;string, {name: string, baseURL: string, apiKeyEnv: string, defaultModel: string, freeTier: boolean, note: string}&gt;</code></dt>
<dd><p>Built-in OpenAI-compatible provider presets.</p>
</dd>
<dt><a href="#DEFAULT_DETERMINISTIC_DIVERGENCE_THRESHOLD">DEFAULT_DETERMINISTIC_DIVERGENCE_THRESHOLD</a> : <code>number</code></dt>
<dd><p>Default maximum delta before deterministic and LLM scores are reconciled upward.</p>
</dd>
</dl>

## Functions

<dl>
<dt><a href="#isRetryable">isRetryable(err)</a> ⇒ <code>boolean</code></dt>
<dd><p>Decide whether an LLM call failure should be retried.</p>
</dd>
<dt><a href="#computeBackoffMs">computeBackoffMs(attempt, retryAfter, [opts])</a> ⇒ <code>number</code></dt>
<dd><p>Compute retry delay from Retry-After or exponential backoff with jitter.</p>
</dd>
<dt><a href="#createSemaphore">createSemaphore(max)</a> ⇒ <code>Object</code></dt>
<dd><p>Create a small async semaphore for bounded parallel LLM dispatch.</p>
</dd>
<dt><a href="#callLLM">callLLM(options)</a> ⇒ <code>Promise.&lt;string&gt;</code></dt>
<dd><p>Call an OpenAI-compatible chat completions endpoint with retries, timeout, optional cache, and abort support.</p>
</dd>
<dt><a href="#callLLMMultiple">callLLMMultiple(options)</a> ⇒ <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code></dt>
<dd><p>Fan out one prompt across multiple model ids with bounded concurrency.</p>
</dd>
<dt><a href="#providerHttpKeyEnvVars">providerHttpKeyEnvVars([providerApiKeyEnv])</a> ⇒ <code>Array.&lt;string&gt;</code></dt>
<dd><p>Build the key lookup order for a selected provider.</p>
</dd>
<dt><a href="#inspectHttpApiKeySource">inspectHttpApiKeySource([options])</a> ⇒ <code>Object</code></dt>
<dd><p>Inspect where an HTTP API key would be read from without exposing the secret.</p>
</dd>
<dt><a href="#resolveHttpApiKey">resolveHttpApiKey([options])</a> ⇒ <code>string</code> | <code>undefined</code></dt>
<dd><p>Resolve the HTTP API key from explicit args, key file, or environment.</p>
</dd>
<dt><a href="#createResponseCache">createResponseCache([options])</a> ⇒ <code>null</code> | <code>Object</code></dt>
<dd><p>Create a filesystem-backed cache for LLM responses.</p>
</dd>
<dt><a href="#responseCacheKey">responseCacheKey([options])</a> ⇒ <code>string</code></dt>
<dd><p>Derive a stable cache key from prompt and provider settings.</p>
</dd>
<dt><a href="#responseCachePath">responseCachePath(dir, key)</a> ⇒ <code>string</code></dt>
<dd><p>Resolve the JSON file path for a response cache key.</p>
</dd>
<dt><a href="#baseURLHost">baseURLHost([baseURL])</a> ⇒ <code>string</code></dt>
<dd><p>Normalize a provider base URL to its host component for cache keys.</p>
</dd>
<dt><a href="#main">main(args)</a> ⇒ <code>Promise.&lt;void&gt;</code></dt>
<dd><p>Run the patina CLI command dispatcher.</p>
</dd>
<dt><a href="#createCancellationController">createCancellationController([options])</a> ⇒ <code>Object</code></dt>
<dd><p>Create a SIGINT-aware cancellation controller for long-running CLI operations.</p>
</dd>
<dt><a href="#resolvePromptMode">resolvePromptMode(mode, context)</a> ⇒ <code>string</code></dt>
<dd><p>Resolve the effective prompt style for backend/model auto mode.</p>
</dd>
<dt><a href="#resolveConfiguredPromptMode">resolveConfiguredPromptMode([options])</a> ⇒ <code>string</code></dt>
<dd><p>Choose the configured prompt mode before backend/model auto-resolution.</p>
</dd>
<dt><a href="#loadConfig">loadConfig([path])</a> ⇒ <code>object</code></dt>
<dd><p>Load default config and merge global/project .patina.yaml overrides.</p>
</dd>
<dt><a href="#getRepoRoot">getRepoRoot()</a> ⇒ <code>string</code></dt>
<dd><p>Return the repository root inferred from this source file location.</p>
</dd>
<dt><a href="#resolveTone">resolveTone(options)</a> ⇒ <code>Object</code></dt>
<dd><p>Resolve CLI/config tone settings into prompt-ready tone metadata.</p>
</dd>
<dt><a href="#inputError">inputError(what, why, action)</a> ⇒ <code>PatinaCliError</code></dt>
<dd><p>Create a user-input error that should exit with code 2.</p>
</dd>
<dt><a href="#runtimeError">runtimeError(what, why, action)</a> ⇒ <code>PatinaCliError</code></dt>
<dd><p>Create a runtime error that should exit with code 1.</p>
</dd>
<dt><a href="#renderCliError">renderCliError(err)</a> ⇒ <code>string</code></dt>
<dd><p>Render any thrown value into the patina CLI error format.</p>
</dd>
<dt><a href="#getExitCode">getExitCode(err, [fallback])</a> ⇒ <code>number</code></dt>
<dd><p>Extract a safe process exit code from an error-like value.</p>
</dd>
<dt><a href="#loadFile">loadFile(path)</a> ⇒ <code>string</code></dt>
<dd><p>Read a UTF-8 text file.</p>
</dd>
<dt><a href="#splitFrontmatter">splitFrontmatter(content)</a> ⇒ <code>Object</code></dt>
<dd><p>Split Markdown-style YAML frontmatter from a document body.</p>
</dd>
<dt><a href="#loadPatterns">loadPatterns(repoRoot, lang, [skipPatterns])</a> ⇒ <code>Array.&lt;{file: string, frontmatter: (object|null), body: string, isStructure: boolean, isScoreOnly: boolean}&gt;</code></dt>
<dd><p>Load language-specific pattern packs from patterns/{lang}-*.md.</p>
</dd>
<dt><a href="#loadProfile">loadProfile(repoRoot, profileName)</a> ⇒ <code>Object</code></dt>
<dd><p>Load a named profile from profiles/{profileName}.md after path validation.</p>
</dd>
<dt><a href="#loadCoreFile">loadCoreFile(repoRoot, filename)</a> ⇒ <code>Object</code></dt>
<dd><p>Load a Markdown file from the core/ directory.</p>
</dd>
<dt><a href="#loadInputText">loadInputText(path)</a> ⇒ <code>string</code></dt>
<dd><p>Read user input text from disk.</p>
</dd>
<dt><a href="#loadVoiceSample">loadVoiceSample(path)</a> ⇒ <code>Object</code></dt>
<dd><p>Load up to three non-empty paragraphs from a voice sample file.</p>
</dd>
<dt><a href="#toneToBackboneProfile">toneToBackboneProfile(tone)</a> ⇒ <code>string</code> | <code>null</code></dt>
<dd><p>Map a resolved named tone to its primary backbone profile.</p>
</dd>
<dt><a href="#createLogger">createLogger([options])</a> ⇒ <code>Object</code></dt>
<dd><p>Create a small stderr logger with text, JSON, and progress modes.</p>
</dd>
<dt><a href="#hashSha256">hashSha256(input)</a> ⇒ <code>string</code> | <code>null</code></dt>
<dd><p>Hash a string or JSON-serializable value with SHA-256.</p>
</dd>
<dt><a href="#buildManifest">buildManifest(options)</a> ⇒ <code>object</code></dt>
<dd><p>Build a pure reproducibility manifest object for one patina run.</p>
</dd>
<dt><a href="#appendResult">appendResult(results, entry)</a> ⇒ <code>Array.&lt;object&gt;</code></dt>
<dd><p>Append one input/output result entry to an existing manifest results array.</p>
</dd>
<dt><a href="#readManifest">readManifest(path)</a> ⇒ <code>object</code></dt>
<dd><p>Read and normalize a manifest JSON file.</p>
</dd>
<dt><a href="#normalizeManifest">normalizeManifest(manifest)</a> ⇒ <code>object</code></dt>
<dd><p>Normalize supported manifest schema versions to stable result shapes.</p>
</dd>
<dt><a href="#writeManifest">writeManifest(dir, manifest, [outputs])</a> ⇒ <code>string</code></dt>
<dd><p>Write manifest.json and optional output files into a run directory.</p>
</dd>
<dt><a href="#runMaxMode">runMaxMode(options)</a> ⇒ <code>Promise.&lt;{type: string, candidates: Array.&lt;object&gt;, best: (object|null), allFailed: boolean, mpsFallback: boolean, timedOut: boolean}&gt;</code></dt>
<dd><p>Run MAX mode: dispatch candidates, score them, and select the best passing result.</p>
</dd>
<dt><a href="#selectBest">selectBest(candidates, [options])</a> ⇒ <code>Object</code></dt>
<dd><p>Select the best MAX candidate, preferring lowest AI score with MPS &gt;= 70.</p>
</dd>
<dt><a href="#resolveMaxModelBackend">resolveMaxModelBackend(model)</a> ⇒ <code>object</code> | <code>null</code></dt>
<dd><p>Resolve an exact MAX model alias to a local backend implementation.</p>
</dd>
<dt><a href="#dispatchMaxCandidates">dispatchMaxCandidates(options)</a> ⇒ <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code></dt>
<dd><p>Dispatch MAX candidates across local backends and HTTP models.</p>
</dd>
<dt><a href="#runOuroboros">runOuroboros(options)</a> ⇒ <code>Promise.&lt;{finalText: string, finalScore: number, iterations: number, reason: string, log: Array.&lt;object&gt;}&gt;</code></dt>
<dd><p>Run the iterative Ouroboros rewrite-and-score loop.</p>
</dd>
<dt><a href="#formatOutput">formatOutput(result, mode, [parsed], [opts])</a> ⇒ <code>string</code></dt>
<dd><p>Format a raw backend result for CLI output mode and requested format.</p>
</dd>
<dt><a href="#extractVariants">extractVariants(body)</a> ⇒ <code>Array.&lt;{id: number, text: string}&gt;</code></dt>
<dd><p>Extract tagged [VARIANT n] blocks from a model response.</p>
</dd>
<dt><a href="#validateScoreWeights">validateScoreWeights(output, configWeights)</a> ⇒ <code>Array.&lt;string&gt;</code></dt>
<dd><p>Validate that a model-emitted score table used configured category weights.</p>
</dd>
<dt><a href="#stripSelfAudit">stripSelfAudit(body, [options])</a> ⇒ <code>string</code></dt>
<dd><p>Remove SELF_AUDIT blocks and unwrap the BODY block from rewrite output.</p>
</dd>
<dt><a href="#buildPrompt">buildPrompt(options)</a> ⇒ <code>string</code></dt>
<dd><p>Build the LLM prompt for rewrite, diff, audit, score, or ouroboros mode.</p>
</dd>
<dt><a href="#isShortText">isShortText(text)</a> ⇒ <code>boolean</code></dt>
<dd><p>Classify whether text should use the short-text scoring boost.</p>
</dd>
<dt><a href="#selectProvider">selectProvider(name)</a> ⇒ <code>object</code> | <code>null</code></dt>
<dd><p>Resolve a provider preset by name.</p>
</dd>
<dt><a href="#resolveProviderConfig">resolveProviderConfig(options)</a> ⇒ <code>Object</code></dt>
<dd><p>Resolve effective API key, base URL, and model from explicit values, provider, and env.</p>
</dd>
<dt><a href="#scoreText">scoreText(options)</a> ⇒ <code>Promise.&lt;object&gt;</code></dt>
<dd><p>Score text for AI-likeness using an LLM JSON scorer plus deterministic shadow signals.</p>
</dd>
<dt><a href="#scoreDeterministicSignals">scoreDeterministicSignals([options])</a> ⇒ <code>object</code> | <code>null</code></dt>
<dd><p>Compute deterministic stylometry/lexicon AI-likeness signals.</p>
</dd>
<dt><a href="#withShadowScore">withShadowScore(parsed, [options])</a> ⇒ <code>object</code></dt>
<dd><p>Merge an LLM score payload with deterministic shadow-score reconciliation.</p>
</dd>
<dt><a href="#reconcileScoreOverall">reconcileScoreOverall([options])</a> ⇒ <code>Object</code></dt>
<dd><p>Reconcile LLM and deterministic overall scores according to config thresholds.</p>
</dd>
<dt><a href="#scoreMPS">scoreMPS(options)</a> ⇒ <code>Promise.&lt;Object&gt;</code></dt>
<dd><p>Score meaning preservation between original and rewritten text.</p>
</dd>
<dt><a href="#interpretScore">interpretScore(score)</a> ⇒ <code>string</code></dt>
<dd><p>Convert a numeric AI-likeness score to a human-readable band.</p>
</dd>
<dt><a href="#lengthRatioPoints">lengthRatioPoints(original, rewritten)</a> ⇒ <code>number</code></dt>
<dd><p>Score rewritten length ratio on the 0-3 fidelity scale.</p>
</dd>
<dt><a href="#scoreFidelity">scoreFidelity(options)</a> ⇒ <code>Promise.&lt;Object&gt;</code></dt>
<dd><p>Score fidelity between original and rewritten text using length plus LLM criteria.</p>
</dd>
<dt><a href="#clamp03">clamp03(v)</a> ⇒ <code>number</code></dt>
<dd><p>Clamp and round a value into the inclusive 0-3 scoring range.</p>
</dd>
<dt><a href="#combinedScore">combinedScore(options)</a> ⇒ <code>number</code></dt>
<dd><p>Combine AI-likeness, inverted fidelity, and optional deterministic score.</p>
</dd>
<dt><a href="#validateProfileName">validateProfileName(name)</a> ⇒ <code>void</code></dt>
<dd><p>Validate a profile name before resolving profiles/{name}.md.</p>
</dd>
<dt><a href="#isLoopbackHost">isLoopbackHost(hostname)</a> ⇒ <code>boolean</code></dt>
<dd><p>Check whether a hostname is localhost or loopback.</p>
</dd>
<dt><a href="#isPrivateOrSpecialIP">isPrivateOrSpecialIP(hostname)</a> ⇒ <code>boolean</code></dt>
<dd><p>Detect literal private, reserved, link-local, metadata, or multicast IP hosts.</p>
</dd>
<dt><a href="#validateBaseURL">validateBaseURL(baseURL, [options])</a> ⇒ <code>void</code></dt>
<dd><p>Validate a provider base URL before sending prompts and bearer tokens.</p>
</dd>
<dt><a href="#shouldAllowInsecureBaseURL">shouldAllowInsecureBaseURL([parsed])</a> ⇒ <code>boolean</code></dt>
<dd><p>Read CLI/env opt-in for non-loopback HTTP base URLs.</p>
</dd>
<dt><a href="#applyInsecureBaseURLOptIn">applyInsecureBaseURLOptIn([parsed])</a> ⇒ <code>void</code></dt>
<dd><p>Persist CLI insecure-base-url opt-in into process.env for downstream calls.</p>
</dd>
<dt><a href="#shouldAllowPrivateBaseURL">shouldAllowPrivateBaseURL([parsed])</a> ⇒ <code>boolean</code></dt>
<dd><p>Read CLI/env opt-in for private or reserved literal IP base URLs.</p>
</dd>
<dt><a href="#applyPrivateBaseURLOptIn">applyPrivateBaseURLOptIn([parsed])</a> ⇒ <code>void</code></dt>
<dd><p>Persist CLI private-base-url opt-in into process.env for downstream calls.</p>
</dd>
</dl>

<a name="DEFAULT_TEMPERATURE"></a>

## DEFAULT\_TEMPERATURE : <code>number</code>
Default sampling temperature for OpenAI-compatible chat completion calls.

**Kind**: global constant
**Example**
```js
const temperature = DEFAULT_TEMPERATURE; // 0.7
```
<a name="HTTP_KEY_ENV_VARS"></a>

## HTTP\_KEY\_ENV\_VARS : <code>Array.&lt;string&gt;</code>
Environment variable names checked for HTTP provider authentication.

**Kind**: global constant
**Example**
```js
const supported = HTTP_KEY_ENV_VARS.includes('OPENAI_API_KEY');
```
<a name="DEFAULT_HTTP_KEY_ENV_VARS"></a>

## DEFAULT\_HTTP\_KEY\_ENV\_VARS : <code>Array.&lt;string&gt;</code>
Default key lookup order for the OpenAI-compatible HTTP provider.

**Kind**: global constant
**Example**
```js
const first = DEFAULT_HTTP_KEY_ENV_VARS[0]; // PATINA_API_KEY
```
<a name="CACHE_SCHEMA_VERSION"></a>

## CACHE\_SCHEMA\_VERSION : <code>number</code>
On-disk response cache schema version.

**Kind**: global constant
**Example**
```js
const version = CACHE_SCHEMA_VERSION;
```
<a name="DEFAULT_CACHE_TTL_SECONDS"></a>

## DEFAULT\_CACHE\_TTL\_SECONDS : <code>number</code>
Default response cache time-to-live: one day.

**Kind**: global constant
**Example**
```js
const ttl = DEFAULT_CACHE_TTL_SECONDS;
```
<a name="defaultLogger"></a>

## defaultLogger : <code>Object</code>
Default stderr logger used by simple callers.

**Kind**: global constant
**Example**
```js
defaultLogger.info('patina.ready', { message: 'ready' });
```
<a name="MANIFEST_SCHEMA_VERSION"></a>

## MANIFEST\_SCHEMA\_VERSION : <code>string</code>
Current reproducibility manifest schema version.

**Kind**: global constant
**Example**
```js
const version = MANIFEST_SCHEMA_VERSION; // '2'
```
<a name="PROVIDERS"></a>

## PROVIDERS : <code>Record.&lt;string, {name: string, baseURL: string, apiKeyEnv: string, defaultModel: string, freeTier: boolean, note: string}&gt;</code>
Built-in OpenAI-compatible provider presets.

**Kind**: global constant
**Example**
```js
const openaiBaseURL = PROVIDERS.openai.baseURL;
```
<a name="DEFAULT_DETERMINISTIC_DIVERGENCE_THRESHOLD"></a>

## DEFAULT\_DETERMINISTIC\_DIVERGENCE\_THRESHOLD : <code>number</code>
Default maximum delta before deterministic and LLM scores are reconciled upward.

**Kind**: global constant
**Example**
```js
const threshold = DEFAULT_DETERMINISTIC_DIVERGENCE_THRESHOLD;
```
<a name="isRetryable"></a>

## isRetryable(err) ⇒ <code>boolean</code>
Decide whether an LLM call failure should be retried.

**Kind**: global function
**Returns**: <code>boolean</code> - True for retryable HTTP statuses, aborts, and common network failures.
**Throws**:

- <code>Error</code> Does not intentionally throw; unexpected Error-like inputs may still propagate JavaScript runtime failures.


| Param | Type | Description |
| --- | --- | --- |
| err | <code>Error</code> \| <code>Object</code> | Error thrown by fetch or [HttpError](HttpError). |

**Example**
```js
const retry = isRetryable(new HttpError(429, 'rate limit', '1'));
```
<a name="computeBackoffMs"></a>

## computeBackoffMs(attempt, retryAfter, [opts]) ⇒ <code>number</code>
Compute retry delay from Retry-After or exponential backoff with jitter.

**Kind**: global function
**Returns**: <code>number</code> - Delay in milliseconds, capped at opts.max.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| attempt | <code>number</code> |  | Zero-based retry attempt. |
| retryAfter | <code>string</code> \| <code>null</code> \| <code>undefined</code> |  | Retry-After seconds or HTTP-date header. |
| [opts] | <code>object</code> |  | Backoff tuning and deterministic test hooks. |
| [opts.base] | <code>number</code> | <code>1000</code> | Initial exponential backoff in milliseconds. |
| [opts.max] | <code>number</code> | <code>30000</code> | Maximum returned delay in milliseconds. |
| [opts.now] | <code>function</code> |  | Clock returning epoch milliseconds. |
| [opts.random] | <code>function</code> |  | Random number provider used for jitter. |

**Example**
```js
const delay = computeBackoffMs(1, '2'); // 2000
```
<a name="createSemaphore"></a>

## createSemaphore(max) ⇒ <code>Object</code>
Create a small async semaphore for bounded parallel LLM dispatch.

**Kind**: global function
**Returns**: <code>Object</code> - Semaphore whose acquire resolves to a release callback.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| max | <code>number</code> | Maximum concurrent acquisitions; values <=0 create an unlimited no-op gate. |

**Example**
```js
const release = await createSemaphore(2).acquire();
release();
```
<a name="callLLM"></a>

## callLLM(options) ⇒ <code>Promise.&lt;string&gt;</code>
Call an OpenAI-compatible chat completions endpoint with retries, timeout, optional cache, and abort support.

**Kind**: global function
**Returns**: <code>Promise.&lt;string&gt;</code> - Assistant message content.
**Throws**:

- <code>HttpError</code> When the provider returns a non-2xx response after retries.
- <code>Error</code> On abort, timeout, malformed provider payload, or base URL validation failure.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| options | <code>object</code> |  | LLM request options. |
| options.prompt | <code>string</code> |  | User prompt sent as the single chat message. |
| [options.apiKey] | <code>string</code> |  | Bearer token for the provider. |
| [options.baseURL] | <code>string</code> | <code>&quot;https://api.openai.com/v1&quot;</code> | OpenAI-compatible API base URL. |
| [options.model] | <code>string</code> | <code>&quot;gpt-4o&quot;</code> | Model id to request. |
| [options.temperature] | <code>number</code> | <code>DEFAULT_TEMPERATURE</code> | Sampling temperature. |
| [options.seed] | <code>number</code> \| <code>string</code> |  | Optional deterministic seed forwarded to the provider. |
| [options.timeout] | <code>number</code> | <code>120000</code> | Per-attempt timeout in milliseconds. |
| [options.maxRetries] | <code>number</code> | <code>2</code> | Retry count after the first attempt. |
| [options.deadline] | <code>number</code> |  | Absolute epoch-millisecond deadline for all attempts. |
| [options.signal] | <code>AbortSignal</code> |  | External cancellation signal. |
| [options.allowInsecureBaseURL] | <code>boolean</code> | <code>false</code> | Allow non-loopback HTTP base URLs. |
| [options.onResponse] | <code>function</code> |  | Callback receiving provider/cache metadata. |
| [options.cache] | <code>object</code> |  | Response cache with get/set methods. |
| [options.sleep] | <code>function</code> |  | Injectable sleep function for tests. |
| [options.now] | <code>function</code> |  | Clock returning epoch milliseconds. |

**Example**
```js
const text = await callLLM({ prompt: 'Rewrite this', apiKey: process.env.OPENAI_API_KEY });
```
<a name="callLLMMultiple"></a>

## callLLMMultiple(options) ⇒ <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code>
Fan out one prompt across multiple model ids with bounded concurrency.

**Kind**: global function
**Returns**: <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code> - Per-model results in input order.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| options | <code>object</code> |  | Multi-model dispatch options. |
| options.prompt | <code>string</code> |  | Prompt to send to each model. |
| options.models | <code>Array.&lt;string&gt;</code> |  | Ordered model ids to call. |
| [options.apiKey] | <code>string</code> |  | Provider API key. |
| [options.baseURL] | <code>string</code> | <code>&quot;https://api.openai.com/v1&quot;</code> | Provider base URL. |
| [options.temperature] | <code>number</code> | <code>DEFAULT_TEMPERATURE</code> | Sampling temperature. |
| [options.seed] | <code>number</code> \| <code>string</code> |  | Optional deterministic seed. |
| [options.timeout] | <code>number</code> |  | Per-call timeout in milliseconds. |
| [options.allowInsecureBaseURL] | <code>boolean</code> | <code>false</code> | Allow non-loopback HTTP base URLs. |
| [options.deadline] | <code>number</code> |  | Absolute epoch-millisecond deadline. |
| [options.signal] | <code>AbortSignal</code> |  | External cancellation signal. |
| [options.maxConcurrency] | <code>number</code> |  | Maximum in-flight model calls. |
| [options.onStart] | <code>function</code> |  | Called with each model before dispatch. |
| [options.onComplete] | <code>function</code> |  | Called with each model and success flag. |
| [options.onResponse] | <code>function</code> |  | Called with response metadata. |
| [options.cache] | <code>object</code> |  | Response cache shared by calls. |
| [options.callLLM] | <code>function</code> |  | Injectable single-model implementation. |

**Example**
```js
const results = await callLLMMultiple({ prompt: 'Hi', models: ['gpt-4o', 'gpt-4o-mini'] });
```
<a name="providerHttpKeyEnvVars"></a>

## providerHttpKeyEnvVars([providerApiKeyEnv]) ⇒ <code>Array.&lt;string&gt;</code>
Build the key lookup order for a selected provider.

**Kind**: global function
**Returns**: <code>Array.&lt;string&gt;</code> - Unique env var names in lookup order.
**Throws**:

- <code>Error</code> Does not intentionally throw; invalid non-string env names can still propagate JavaScript runtime failures.


| Param | Type | Description |
| --- | --- | --- |
| [providerApiKeyEnv] | <code>string</code> | Provider-specific key env var, such as GEMINI_API_KEY. |

**Example**
```js
const vars = providerHttpKeyEnvVars('GEMINI_API_KEY');
```
<a name="inspectHttpApiKeySource"></a>

## inspectHttpApiKeySource([options]) ⇒ <code>Object</code>
Inspect where an HTTP API key would be read from without exposing the secret.

**Kind**: global function
**Returns**: <code>Object</code> - Source diagnostics.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Inspection options. |
| [options.env] | <code>object</code> | <code>process.env</code> | Environment map to inspect. |
| [options.readFile] | <code>function</code> |  | File reader for PATINA_API_KEY_FILE. |
| [options.envVars] | <code>Array.&lt;string&gt;</code> | <code>DEFAULT_HTTP_KEY_ENV_VARS</code> | Env vars to check. |

**Example**
```js
const source = inspectHttpApiKeySource({ env: { PATINA_API_KEY: 'sk-...' } });
```
<a name="resolveHttpApiKey"></a>

## resolveHttpApiKey([options]) ⇒ <code>string</code> \| <code>undefined</code>
Resolve the HTTP API key from explicit args, key file, or environment.

**Kind**: global function
**Returns**: <code>string</code> \| <code>undefined</code> - Resolved key value, or undefined when unauthenticated.
**Throws**:

- <code>PatinaCliError</code> When the configured key file cannot be read or is empty.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Resolution options. |
| [options.explicitApiKey] | <code>string</code> |  | Deprecated direct key value. |
| [options.apiKeyFile] | <code>string</code> |  | Explicit key file path. |
| [options.env] | <code>object</code> | <code>process.env</code> | Environment map. |
| [options.readFile] | <code>function</code> |  | File reader for key files. |
| [options.envVars] | <code>Array.&lt;string&gt;</code> | <code>DEFAULT_HTTP_KEY_ENV_VARS</code> | Env var lookup order. |

**Example**
```js
const key = resolveHttpApiKey({ env: process.env });
```
<a name="createResponseCache"></a>

## createResponseCache([options]) ⇒ <code>null</code> \| <code>Object</code>
Create a filesystem-backed cache for LLM responses.

**Kind**: global function
**Returns**: <code>null</code> \| <code>Object</code> - Cache object or null.
**Throws**:

- <code>Error</code> Propagates filesystem or JSON errors when cache entries are read or written through the returned object.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Cache options. |
| [options.dir] | <code>string</code> |  | Directory for cache JSON files; returns null when omitted. |
| [options.ttlSeconds] | <code>number</code> | <code>DEFAULT_CACHE_TTL_SECONDS</code> | Entry TTL in seconds. |
| [options.now] | <code>function</code> |  | Clock returning epoch milliseconds. |

**Example**
```js
const cache = createResponseCache({ dir: '.patina-cache' });
```
<a name="responseCacheKey"></a>

## responseCacheKey([options]) ⇒ <code>string</code>
Derive a stable cache key from prompt and provider settings.

**Kind**: global function
**Returns**: <code>string</code> - sha256-prefixed cache key.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [options] | <code>object</code> | Cache-key inputs. |
| [options.prompt] | <code>string</code> | Prompt text. |
| [options.model] | <code>string</code> | Model id. |
| [options.temperature] | <code>number</code> | Sampling temperature. |
| [options.baseURL] | <code>string</code> | Provider base URL. |

**Example**
```js
const key = responseCacheKey({ prompt: 'Hi', model: 'gpt-4o' });
```
<a name="responseCachePath"></a>

## responseCachePath(dir, key) ⇒ <code>string</code>
Resolve the JSON file path for a response cache key.

**Kind**: global function
**Returns**: <code>string</code> - Absolute or relative cache JSON path under dir.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| dir | <code>string</code> | Cache directory. |
| key | <code>string</code> | sha256-prefixed or raw cache key. |

**Example**
```js
const path = responseCachePath('.cache', 'sha256:abc');
```
<a name="baseURLHost"></a>

## baseURLHost([baseURL]) ⇒ <code>string</code>
Normalize a provider base URL to its host component for cache keys.

**Kind**: global function
**Returns**: <code>string</code> - Parsed host, or the original string when parsing fails.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [baseURL] | <code>string</code> | Provider base URL. |

**Example**
```js
const host = baseURLHost('https://api.openai.com/v1');
```
<a name="main"></a>

## main(args) ⇒ <code>Promise.&lt;void&gt;</code>
Run the patina CLI command dispatcher.

**Kind**: global function
**Returns**: <code>Promise.&lt;void&gt;</code> - Resolves after command output is written.
**Throws**:

- <code>Error</code> For validation, provider, file, or runtime failures.


| Param | Type | Description |
| --- | --- | --- |
| args | <code>Array.&lt;string&gt;</code> | Command-line arguments excluding node and script path. |

**Example**
```js
await main(['--help']);
```
<a name="createCancellationController"></a>

## createCancellationController([options]) ⇒ <code>Object</code>
Create a SIGINT-aware cancellation controller for long-running CLI operations.

**Kind**: global function
**Returns**: <code>Object</code> - Controller facade.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Cancellation integration points. |
| [options.processObj] | <code>NodeJS.Process</code> | <code>process</code> | Process-like object used for signal listeners. |
| [options.stderr] | <code>NodeJS.WritableStream</code> | <code>process.stderr</code> | Stream for fallback cancel messages. |
| [options.logger] | <code>object</code> \| <code>null</code> |  | Optional patina logger. |

**Example**
```js
const cancellation = createCancellationController();
cancellation.install();
```
<a name="resolvePromptMode"></a>

## resolvePromptMode(mode, context) ⇒ <code>string</code>
Resolve the effective prompt style for backend/model auto mode.

**Kind**: global function
**Returns**: <code>string</code> - Resolved prompt mode.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| mode | <code>string</code> | Requested prompt mode: auto, strict, or minimal. |
| context | <code>object</code> | Backend selection context. |
| [context.backend] | <code>string</code> | Backend name. |
| [context.model] | <code>string</code> | Model id. |

**Example**
```js
const mode = resolvePromptMode('auto', { model: 'gemini-1.5-flash' });
```
<a name="resolveConfiguredPromptMode"></a>

## resolveConfiguredPromptMode([options]) ⇒ <code>string</code>
Choose the configured prompt mode before backend/model auto-resolution.

**Kind**: global function
**Returns**: <code>string</code> - Requested prompt mode.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Prompt-mode sources. |
| [options.cliPromptMode] | <code>string</code> |  | CLI --prompt-mode value. |
| [options.configPromptMode] | <code>string</code> |  | Config prompt-mode value. |
| [options.isMaxMode] | <code>boolean</code> | <code>false</code> | Whether MAX mode is active. |

**Example**
```js
const requested = resolveConfiguredPromptMode({ isMaxMode: true });
```
<a name="loadConfig"></a>

## loadConfig([path]) ⇒ <code>object</code>
Load default config and merge global/project .patina.yaml overrides.

**Kind**: global function
**Returns**: <code>object</code> - Merged patina configuration object.
**Throws**:

- <code>Error</code> When a config file is missing, invalid YAML, or not a mapping.


| Param | Type | Description |
| --- | --- | --- |
| [path] | <code>string</code> | Base YAML config path. |

**Example**
```js
const config = loadConfig();
```
<a name="getRepoRoot"></a>

## getRepoRoot() ⇒ <code>string</code>
Return the repository root inferred from this source file location.

**Kind**: global function
**Returns**: <code>string</code> - Absolute repository root path.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.

**Example**
```js
const root = getRepoRoot();
```
<a name="resolveTone"></a>

## resolveTone(options) ⇒ <code>Object</code>
Resolve CLI/config tone settings into prompt-ready tone metadata.

**Kind**: global function
**Returns**: <code>Object</code> - Tone metadata.
**Throws**:

- <code>Error</code> When cliTone or configTone is not supported.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Tone inputs. |
| [options.cliTone] | <code>string</code> \| <code>null</code> | CLI tone override. |
| [options.configTone] | <code>string</code> \| <code>null</code> | Configured tone value. |
| [options.lang] | <code>string</code> | Active language code. |

**Example**
```js
const tone = resolveTone({ cliTone: 'casual', lang: 'ko' });
```
<a name="inputError"></a>

## inputError(what, why, action) ⇒ <code>PatinaCliError</code>
Create a user-input error that should exit with code 2.

**Kind**: global function
**Returns**: <code>PatinaCliError</code> - Structured input error.
**Throws**:

- <code>Error</code> Does not intentionally throw; returns an Error instance for callers to throw.


| Param | Type | Description |
| --- | --- | --- |
| what | <code>string</code> | Short failure headline. |
| why | <code>string</code> | Explanation of the invalid input. |
| action | <code>string</code> | Suggested user action. |

**Example**
```js
throw inputError('missing input', 'No file was provided.', 'Pass a file path.');
```
<a name="runtimeError"></a>

## runtimeError(what, why, action) ⇒ <code>PatinaCliError</code>
Create a runtime error that should exit with code 1.

**Kind**: global function
**Returns**: <code>PatinaCliError</code> - Structured runtime error.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| what | <code>string</code> | Short failure headline. |
| why | <code>string</code> | Explanation of the runtime failure. |
| action | <code>string</code> | Suggested user action. |

**Example**
```js
throw runtimeError('provider failed', 'The API timed out.', 'Retry later.');
```
<a name="renderCliError"></a>

## renderCliError(err) ⇒ <code>string</code>
Render any thrown value into the patina CLI error format.

**Kind**: global function
**Returns**: <code>string</code> - Multi-line user-facing error text.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| err | <code>unknown</code> | Error-like value to render. |

**Example**
```js
const message = renderCliError(inputError('bad flag', 'Unknown flag.', 'Run --help.'));
```
<a name="getExitCode"></a>

## getExitCode(err, [fallback]) ⇒ <code>number</code>
Extract a safe process exit code from an error-like value.

**Kind**: global function
**Returns**: <code>number</code> - Non-negative integer exit code.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| err | <code>unknown</code> |  | Error-like value. |
| [fallback] | <code>number</code> | <code>1</code> | Exit code used when err.exitCode is absent or invalid. |

**Example**
```js
const code = getExitCode(inputError('bad', 'why', 'fix')); // 2
```
<a name="loadFile"></a>

## loadFile(path) ⇒ <code>string</code>
Read a UTF-8 text file.

**Kind**: global function
**Returns**: <code>string</code> - File contents.
**Throws**:

- <code>Error</code> When the file cannot be read.


| Param | Type | Description |
| --- | --- | --- |
| path | <code>string</code> | File path to read. |

**Example**
```js
const markdown = loadFile('README.md');
```
<a name="splitFrontmatter"></a>

## splitFrontmatter(content) ⇒ <code>Object</code>
Split Markdown-style YAML frontmatter from a document body.

**Kind**: global function
**Returns**: <code>Object</code> - Parsed frontmatter and trimmed body.
**Throws**:

- <code>Error</code> When YAML frontmatter is invalid.


| Param | Type | Description |
| --- | --- | --- |
| content | <code>string</code> | File contents. |

**Example**
```js
const { frontmatter, body } = splitFrontmatter('---\ntitle: x\n---\nBody');
```
<a name="loadPatterns"></a>

## loadPatterns(repoRoot, lang, [skipPatterns]) ⇒ <code>Array.&lt;{file: string, frontmatter: (object\|null), body: string, isStructure: boolean, isScoreOnly: boolean}&gt;</code>
Load language-specific pattern packs from patterns/{lang}-*.md.

**Kind**: global function
**Returns**: <code>Array.&lt;{file: string, frontmatter: (object\|null), body: string, isStructure: boolean, isScoreOnly: boolean}&gt;</code> - Pattern packs.
**Throws**:

- <code>Error</code> When the patterns directory or a pattern file cannot be read.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| repoRoot | <code>string</code> |  | Repository root path. |
| lang | <code>string</code> |  | Language code, such as ko, en, zh, or ja. |
| [skipPatterns] | <code>Array.&lt;string&gt;</code> | <code>[]</code> | Pack names to omit, without .md. |

**Example**
```js
const patterns = loadPatterns(getRepoRoot(), 'en');
```
<a name="loadProfile"></a>

## loadProfile(repoRoot, profileName) ⇒ <code>Object</code>
Load a named profile from profiles/{profileName}.md after path validation.

**Kind**: global function
**Returns**: <code>Object</code> - Parsed profile document.
**Throws**:

- <code>Error</code> When the profile name is invalid or the file cannot be read.


| Param | Type | Description |
| --- | --- | --- |
| repoRoot | <code>string</code> | Repository root path. |
| profileName | <code>string</code> | Profile file stem. |

**Example**
```js
const profile = loadProfile(getRepoRoot(), 'default');
```
<a name="loadCoreFile"></a>

## loadCoreFile(repoRoot, filename) ⇒ <code>Object</code>
Load a Markdown file from the core/ directory.

**Kind**: global function
**Returns**: <code>Object</code> - Parsed core document.
**Throws**:

- <code>Error</code> When the file cannot be read or frontmatter is invalid.


| Param | Type | Description |
| --- | --- | --- |
| repoRoot | <code>string</code> | Repository root path. |
| filename | <code>string</code> | Core filename, such as scoring.md. |

**Example**
```js
const scoring = loadCoreFile(getRepoRoot(), 'scoring.md');
```
<a name="loadInputText"></a>

## loadInputText(path) ⇒ <code>string</code>
Read user input text from disk.

**Kind**: global function
**Returns**: <code>string</code> - UTF-8 input text.
**Throws**:

- <code>Error</code> When the file cannot be read.


| Param | Type | Description |
| --- | --- | --- |
| path | <code>string</code> | Input file path. |

**Example**
```js
const text = loadInputText('draft.md');
```
<a name="loadVoiceSample"></a>

## loadVoiceSample(path) ⇒ <code>Object</code>
Load up to three non-empty paragraphs from a voice sample file.

**Kind**: global function
**Returns**: <code>Object</code> - Voice sample payload.
**Throws**:

- <code>Error</code> When the file is unreadable or has no non-empty paragraphs.


| Param | Type | Description |
| --- | --- | --- |
| path | <code>string</code> | Voice sample file path. |

**Example**
```js
const sample = loadVoiceSample('voice.md');
```
<a name="toneToBackboneProfile"></a>

## toneToBackboneProfile(tone) ⇒ <code>string</code> \| <code>null</code>
Map a resolved named tone to its primary backbone profile.

**Kind**: global function
**Returns**: <code>string</code> \| <code>null</code> - Profile name, or null when no mapping exists.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| tone | <code>string</code> | Tone name. |

**Example**
```js
const profile = toneToBackboneProfile('casual'); // blog
```
<a name="createLogger"></a>

## createLogger([options]) ⇒ <code>Object</code>
Create a small stderr logger with text, JSON, and progress modes.

**Kind**: global function
**Returns**: <code>Object</code> - Logger facade.
**Throws**:

- <code>Error</code> Propagates stream write errors from the configured output stream.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Logger options. |
| [options.level] | <code>string</code> | <code>&quot;info&quot;</code> | Minimum log level. |
| [options.quiet] | <code>boolean</code> | <code>false</code> | Suppress all log output. |
| [options.json] | <code>boolean</code> | <code>false</code> | Emit structured JSON records. |
| [options.stream] | <code>NodeJS.WritableStream</code> | <code>process.stderr</code> | Progress stream. |

**Example**
```js
const logger = createLogger({ json: true });
logger.info('event', { message: 'ready' });
```
<a name="hashSha256"></a>

## hashSha256(input) ⇒ <code>string</code> \| <code>null</code>
Hash a string or JSON-serializable value with SHA-256.

**Kind**: global function
**Returns**: <code>string</code> \| <code>null</code> - sha256-prefixed digest or null.
**Throws**:

- <code>TypeError</code> When a non-string value cannot be JSON-serialized.


| Param | Type | Description |
| --- | --- | --- |
| input | <code>unknown</code> | Value to hash; nullish values return null. |

**Example**
```js
const hash = hashSha256('prompt');
```
<a name="buildManifest"></a>

## buildManifest(options) ⇒ <code>object</code>
Build a pure reproducibility manifest object for one patina run.

**Kind**: global function
**Returns**: <code>object</code> - Manifest body ready to serialize.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Resolved run metadata. |
| options.patinaVersion | <code>string</code> | Package version. |
| options.mode | <code>string</code> | Output mode. |
| options.lang | <code>string</code> | Language code. |
| options.profile | <code>string</code> | Profile name. |
| [options.provider] | <code>string</code> | Provider preset name. |
| [options.backend] | <code>string</code> | Backend name. |
| [options.model] | <code>string</code> | Model id. |
| [options.configPath] | <code>string</code> | Config file path. |
| [options.config] | <code>object</code> | Effective config. |
| [options.patterns] | <code>Array.&lt;object&gt;</code> | Loaded pattern packs. |
| [options.results] | <code>Array.&lt;object&gt;</code> | Manifest result entries. |
| options.startedAt | <code>string</code> | ISO start timestamp. |
| [options.finishedAt] | <code>string</code> | ISO finish timestamp. |
| [options.temperature] | <code>number</code> \| <code>null</code> | Sampling temperature. |
| [options.seed] | <code>number</code> \| <code>string</code> \| <code>null</code> | Model seed. |

**Example**
```js
const manifest = buildManifest({ patinaVersion: '3.11.0', mode: 'rewrite', lang: 'en', profile: 'default', startedAt: new Date().toISOString() });
```
<a name="appendResult"></a>

## appendResult(results, entry) ⇒ <code>Array.&lt;object&gt;</code>
Append one input/output result entry to an existing manifest results array.

**Kind**: global function
**Returns**: <code>Array.&lt;object&gt;</code> - The same results array after mutation.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| results | <code>Array.&lt;object&gt;</code> | Mutable manifest results array. |
| entry | <code>object</code> | Result metadata. |
| entry.inputPath | <code>string</code> | Original input path. |
| entry.prompt | <code>string</code> | Prompt text. |
| entry.outputRef | <code>string</code> | Output file or stream reference. |
| entry.response | <code>string</code> | Model response text. |
| [entry.tokensIn] | <code>number</code> \| <code>null</code> | Input token count. |
| [entry.tokensOut] | <code>number</code> \| <code>null</code> | Output token count. |
| [entry.temperature] | <code>number</code> \| <code>null</code> | Sampling temperature. |
| [entry.seed] | <code>number</code> \| <code>string</code> \| <code>null</code> | Model seed. |
| [entry.cost] | <code>number</code> \| <code>null</code> | Estimated cost. |
| [entry.scores] | <code>object</code> | Score payload. |
| [entry.iterationLog] | <code>Array.&lt;object&gt;</code> | Ouroboros iteration log. |
| [entry.calls] | <code>Array.&lt;object&gt;</code> | Provider call metadata. |

**Example**
```js
appendResult(results, { inputPath: 'in.md', prompt: 'p', outputRef: 'out.md', response: 'r' });
```
<a name="readManifest"></a>

## readManifest(path) ⇒ <code>object</code>
Read and normalize a manifest JSON file.

**Kind**: global function
**Returns**: <code>object</code> - Normalized manifest.
**Throws**:

- <code>Error</code> When JSON is invalid, unreadable, or schema is unsupported.


| Param | Type | Description |
| --- | --- | --- |
| path | <code>string</code> | Manifest JSON path. |

**Example**
```js
const manifest = readManifest('runs/latest/manifest.json');
```
<a name="normalizeManifest"></a>

## normalizeManifest(manifest) ⇒ <code>object</code>
Normalize supported manifest schema versions to stable result shapes.

**Kind**: global function
**Returns**: <code>object</code> - Manifest with normalized results.
**Throws**:

- <code>Error</code> When manifest is not an object or schema version is unsupported.


| Param | Type | Description |
| --- | --- | --- |
| manifest | <code>object</code> | Manifest object to normalize. |

**Example**
```js
const normalized = normalizeManifest({ manifestVersion: '1', results: [] });
```
<a name="writeManifest"></a>

## writeManifest(dir, manifest, [outputs]) ⇒ <code>string</code>
Write manifest.json and optional output files into a run directory.

**Kind**: global function
**Returns**: <code>string</code> - Path to the written manifest.json.
**Throws**:

- <code>Error</code> When the directory or files cannot be written.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| dir | <code>string</code> |  | Destination directory. |
| manifest | <code>object</code> |  | Manifest object to serialize. |
| [outputs] | <code>Array.&lt;{name: string, content: string}&gt;</code> | <code>[]</code> | Extra files to write beside manifest.json. |

**Example**
```js
const path = writeManifest('runs/latest', manifest, [{ name: 'output.md', content: 'Done' }]);
```
<a name="runMaxMode"></a>

## runMaxMode(options) ⇒ <code>Promise.&lt;{type: string, candidates: Array.&lt;object&gt;, best: (object\|null), allFailed: boolean, mpsFallback: boolean, timedOut: boolean}&gt;</code>
Run MAX mode: dispatch candidates, score them, and select the best passing result.

**Kind**: global function
**Returns**: <code>Promise.&lt;{type: string, candidates: Array.&lt;object&gt;, best: (object\|null), allFailed: boolean, mpsFallback: boolean, timedOut: boolean}&gt;</code> - MAX result.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| options | <code>object</code> |  | MAX mode options. |
| options.prompt | <code>string</code> |  | Prompt to send to each model. |
| options.sourceText | <code>string</code> |  | Original source text for MPS scoring. |
| options.models | <code>Array.&lt;string&gt;</code> |  | Ordered model ids or local backend aliases. |
| [options.apiKey] | <code>string</code> |  | Provider API key. |
| [options.baseURL] | <code>string</code> |  | Provider base URL. |
| options.config | <code>object</code> |  | Effective config. |
| options.patterns | <code>Array.&lt;object&gt;</code> |  | Loaded pattern packs. |
| [options.maxConcurrency] | <code>number</code> |  | Maximum concurrent candidates. |
| [options.wallClockBudgetMs] | <code>number</code> | <code>300000</code> | Total MAX-mode budget. |
| [options.callLLM] | <code>function</code> |  | HTTP LLM implementation. |
| [options.now] | <code>function</code> |  | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> |  | Sleep helper for tests. |
| [options.callLLMMultipleImpl] | <code>function</code> |  | Injectable dispatcher. |
| [options.modelBackendResolver] | <code>function</code> |  | Resolver for local aliases. |
| [options.scoreTextImpl] | <code>function</code> |  | Injectable AI-likeness scorer. |
| [options.scoreMPSImpl] | <code>function</code> |  | Injectable MPS scorer. |
| [options.signal] | <code>AbortSignal</code> |  | External cancellation signal. |
| [options.logger] | <code>object</code> |  | patina logger. |

**Example**
```js
const result = await runMaxMode({ prompt, sourceText, models: ['gpt-4o'], config, patterns });
```
<a name="selectBest"></a>

## selectBest(candidates, [options]) ⇒ <code>Object</code>
Select the best MAX candidate, preferring lowest AI score with MPS >= 70.

**Kind**: global function
**Returns**: <code>Object</code> - Selected candidate and whether MPS fallback was used.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| candidates | <code>Array.&lt;object&gt;</code> | Candidate result objects. |
| [options] | <code>object</code> | Selection options. |
| [options.log] | <code>function</code> | Tie-break logger. |

**Example**
```js
const { candidate } = selectBest([{ ok: true, model: 'a', aiScore: 20, mps: 90 }]);
```
<a name="resolveMaxModelBackend"></a>

## resolveMaxModelBackend(model) ⇒ <code>object</code> \| <code>null</code>
Resolve an exact MAX model alias to a local backend implementation.

**Kind**: global function
**Returns**: <code>object</code> \| <code>null</code> - Backend implementation, or null for HTTP models.
**Throws**:

- <code>Error</code> When the matching backend is unavailable.


| Param | Type | Description |
| --- | --- | --- |
| model | <code>string</code> | Model id or alias. |

**Example**
```js
const backend = resolveMaxModelBackend('claude-cli');
```
<a name="dispatchMaxCandidates"></a>

## dispatchMaxCandidates(options) ⇒ <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code>
Dispatch MAX candidates across local backends and HTTP models.

**Kind**: global function
**Returns**: <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code> - Candidate results.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Dispatch options. |
| options.prompt | <code>string</code> | Prompt to send. |
| options.models | <code>Array.&lt;string&gt;</code> | Ordered model ids. |
| [options.apiKey] | <code>string</code> | Provider API key. |
| [options.baseURL] | <code>string</code> | Provider base URL. |
| [options.maxConcurrency] | <code>number</code> | Maximum concurrent dispatches. |
| [options.deadline] | <code>number</code> | Absolute epoch-millisecond deadline. |
| [options.signal] | <code>AbortSignal</code> | External cancellation signal. |
| [options.callLLM] | <code>function</code> | HTTP LLM implementation. |
| [options.modelBackendResolver] | <code>function</code> | Local backend resolver. |
| [options.now] | <code>function</code> | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> | Sleep helper. |
| [options.onStart] | <code>function</code> | Per-model start callback. |
| [options.onComplete] | <code>function</code> | Per-model completion callback. |

**Example**
```js
const candidates = await dispatchMaxCandidates({ prompt: 'Hi', models: ['gpt-4o'] });
```
<a name="runOuroboros"></a>

## runOuroboros(options) ⇒ <code>Promise.&lt;{finalText: string, finalScore: number, iterations: number, reason: string, log: Array.&lt;object&gt;}&gt;</code>
Run the iterative Ouroboros rewrite-and-score loop.

**Kind**: global function
**Returns**: <code>Promise.&lt;{finalText: string, finalScore: number, iterations: number, reason: string, log: Array.&lt;object&gt;}&gt;</code> - Final text and iteration log.
**Throws**:

- <code>Error</code> When model calls or scoring fail outside handled schema fallbacks.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Ouroboros options. |
| options.config | <code>object</code> | Effective config with ouroboros settings. |
| options.patterns | <code>Array.&lt;object&gt;</code> | Loaded pattern packs. |
| options.profile | <code>object</code> \| <code>null</code> | Parsed profile. |
| options.voice | <code>object</code> \| <code>null</code> | Parsed voice guide. |
| [options.voiceSample] | <code>object</code> \| <code>null</code> | Optional voice sample payload. |
| options.scoring | <code>object</code> \| <code>null</code> | Parsed scoring guide. |
| options.text | <code>string</code> | Source text to improve. |
| [options.apiKey] | <code>string</code> | Provider API key. |
| [options.baseURL] | <code>string</code> | Provider base URL. |
| [options.model] | <code>string</code> | Model id. |
| [options.callLLM] | <code>function</code> | LLM implementation. |
| [options.now] | <code>function</code> | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> | Sleep helper for tests. |
| [options.signal] | <code>AbortSignal</code> | External cancellation signal. |
| [options.logger] | <code>object</code> | patina logger. |

**Example**
```js
const result = await runOuroboros({ config, patterns, profile, voice, scoring, text });
```
<a name="formatOutput"></a>

## formatOutput(result, mode, [parsed], [opts]) ⇒ <code>string</code>
Format a raw backend result for CLI output mode and requested format.

**Kind**: global function
**Returns**: <code>string</code> - User-facing formatted output.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| result | <code>string</code> \| <code>object</code> |  | Backend result or structured mode result. |
| mode | <code>string</code> |  | Output mode: rewrite, diff, audit, score, or ouroboros. |
| [parsed] | <code>object</code> | <code>{}</code> | Parsed CLI options. |
| [opts] | <code>object</code> | <code>{}</code> | Formatting options. |
| [opts.tone] | <code>object</code> \| <code>null</code> |  | Tone metadata to append. |
| [opts.logger] | <code>object</code> |  | Logger for output warnings. |
| [opts.env] | <code>object</code> |  | Environment map for color decisions. |
| [opts.stdout] | <code>object</code> |  | Stdout-like stream for color decisions. |

**Example**
```js
const output = formatOutput('[BODY]Hi[/BODY]', 'rewrite');
```
<a name="extractVariants"></a>

## extractVariants(body) ⇒ <code>Array.&lt;{id: number, text: string}&gt;</code>
Extract tagged [VARIANT n] blocks from a model response.

**Kind**: global function
**Returns**: <code>Array.&lt;{id: number, text: string}&gt;</code> - Variants sorted by numeric id.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| body | <code>string</code> | Raw model response. |

**Example**
```js
const variants = extractVariants('[VARIANT 1]\nHello\n[/VARIANT]');
```
<a name="validateScoreWeights"></a>

## validateScoreWeights(output, configWeights) ⇒ <code>Array.&lt;string&gt;</code>
Validate that a model-emitted score table used configured category weights.

**Kind**: global function
**Returns**: <code>Array.&lt;string&gt;</code> - Human-readable warnings for missing, mismatched, or unexpected categories.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| output | <code>string</code> | Score-mode markdown output. |
| configWeights | <code>object</code> | Expected category weight map. |

**Example**
```js
const warnings = validateScoreWeights('| content | 0.4 | 1 | 10 | 4 |', { content: 0.4 });
```
<a name="stripSelfAudit"></a>

## stripSelfAudit(body, [options]) ⇒ <code>string</code>
Remove SELF_AUDIT blocks and unwrap the BODY block from rewrite output.

**Kind**: global function
**Returns**: <code>string</code> - Clean user-facing body text.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| body | <code>string</code> | Raw model response. |
| [options] | <code>object</code> | Strip options. |
| [options.logger] | <code>object</code> | Logger for malformed output warnings. |

**Example**
```js
const clean = stripSelfAudit('[BODY]Hello[/BODY]\n[SELF_AUDIT]ok[/SELF_AUDIT]');
```
<a name="buildPrompt"></a>

## buildPrompt(options) ⇒ <code>string</code>
Build the LLM prompt for rewrite, diff, audit, score, or ouroboros mode.

**Kind**: global function
**Returns**: <code>string</code> - Complete prompt text.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| options | <code>object</code> |  | Prompt inputs. |
| options.config | <code>object</code> |  | Effective patina config. |
| options.patterns | <code>Array.&lt;object&gt;</code> |  | Loaded pattern packs. |
| options.profile | <code>object</code> \| <code>null</code> |  | Parsed profile document. |
| options.voice | <code>object</code> \| <code>null</code> |  | Parsed voice guide. |
| [options.voiceSample] | <code>object</code> \| <code>null</code> |  | Optional voice sample payload. |
| options.scoring | <code>object</code> \| <code>null</code> |  | Parsed scoring guide. |
| options.text | <code>string</code> |  | Input text. |
| [options.mode] | <code>string</code> | <code>&quot;rewrite&quot;</code> | Output mode. |
| [options.tone] | <code>object</code> \| <code>null</code> | <code></code> | Tone resolution metadata. |
| [options.promptMode] | <code>string</code> | <code>&quot;strict&quot;</code> | Prompt mode: strict or minimal. |
| [options.variants] | <code>number</code> | <code>1</code> | Number of rewrite variants. |

**Example**
```js
const prompt = buildPrompt({ config, patterns, profile, voice, scoring, text: 'Draft' });
```
<a name="isShortText"></a>

## isShortText(text) ⇒ <code>boolean</code>
Classify whether text should use the short-text scoring boost.

**Kind**: global function
**Returns**: <code>boolean</code> - True when text is <=200 non-whitespace chars or <=3 paragraphs.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| text | <code>string</code> | Text to inspect. |

**Example**
```js
const short = isShortText('A short note.');
```
<a name="selectProvider"></a>

## selectProvider(name) ⇒ <code>object</code> \| <code>null</code>
Resolve a provider preset by name.

**Kind**: global function
**Returns**: <code>object</code> \| <code>null</code> - Provider preset or null.
**Throws**:

- <code>PatinaCliError</code> When name is unknown.


| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> \| <code>null</code> \| <code>undefined</code> | Provider name; falsy returns null. |

**Example**
```js
const provider = selectProvider('openai');
```
<a name="resolveProviderConfig"></a>

## resolveProviderConfig(options) ⇒ <code>Object</code>
Resolve effective API key, base URL, and model from explicit values, provider, and env.

**Kind**: global function
**Returns**: <code>Object</code> - Resolved provider config.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Provider resolution inputs. |
| [options.provider] | <code>object</code> \| <code>null</code> | Provider preset from [selectProvider](#selectProvider). |
| [options.apiKey] | <code>string</code> | Explicit API key. |
| [options.baseURL] | <code>string</code> | Explicit base URL. |
| [options.model] | <code>string</code> | Explicit model id. |

**Example**
```js
const resolved = resolveProviderConfig({ provider: selectProvider('openai') });
```
<a name="scoreText"></a>

## scoreText(options) ⇒ <code>Promise.&lt;object&gt;</code>
Score text for AI-likeness using an LLM JSON scorer plus deterministic shadow signals.

**Kind**: global function
**Returns**: <code>Promise.&lt;object&gt;</code> - Score payload with overall, interpretation, llmScore, and deterministicScore.
**Throws**:

- <code>Error</code> When the operation is aborted.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Scoring options. |
| options.text | <code>string</code> | Text to score. |
| options.config | <code>object</code> | Effective patina config. |
| options.patterns | <code>Array.&lt;object&gt;</code> | Loaded pattern packs, retained for scorer compatibility. |
| [options.apiKey] | <code>string</code> | Provider API key. |
| [options.baseURL] | <code>string</code> | Provider base URL. |
| [options.model] | <code>string</code> | Model id. |
| [options.deadline] | <code>number</code> | Absolute epoch-millisecond deadline. |
| [options.signal] | <code>AbortSignal</code> | External cancellation signal. |
| [options.callLLM] | <code>function</code> | Injectable LLM implementation. |
| [options.logger] | <code>object</code> | patina logger. |
| [options.now] | <code>function</code> | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> | Sleep helper for tests. |

**Example**
```js
const score = await scoreText({ text: 'Draft', config, patterns, callLLM: async () => '{"categories":{},"overall":20,"interpretation":"mostly human"}' });
```
<a name="scoreDeterministicSignals"></a>

## scoreDeterministicSignals([options]) ⇒ <code>object</code> \| <code>null</code>
Compute deterministic stylometry/lexicon AI-likeness signals.

**Kind**: global function
**Returns**: <code>object</code> \| <code>null</code> - Deterministic score payload, skipped payload, or null when disabled.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Deterministic scoring options. |
| [options.text] | <code>string</code> |  | Text to analyze. |
| [options.config] | <code>object</code> | <code>{}</code> | Effective config. |
| [options.repoRoot] | <code>string</code> |  | Repository root for analyzer resources. |
| [options.analyzer] | <code>function</code> |  | Analyzer implementation. |

**Example**
```js
const deterministic = scoreDeterministicSignals({ text: 'Draft', config });
```
<a name="withShadowScore"></a>

## withShadowScore(parsed, [options]) ⇒ <code>object</code>
Merge an LLM score payload with deterministic shadow-score reconciliation.

**Kind**: global function
**Returns**: <code>object</code> - Score payload preserving llmScore and deterministicScore details.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| parsed | <code>object</code> |  | Parsed LLM scoring JSON. |
| [options] | <code>object</code> |  | Reconciliation options. |
| [options.deterministicScore] | <code>object</code> \| <code>null</code> |  | Deterministic score payload. |
| [options.config] | <code>object</code> | <code>{}</code> | Effective config. |
| [options.logger] | <code>object</code> |  | Logger for reconciliation warnings. |

**Example**
```js
const score = withShadowScore({ overall: 20 }, { deterministicScore: { overall: 25 } });
```
<a name="reconcileScoreOverall"></a>

## reconcileScoreOverall([options]) ⇒ <code>Object</code>
Reconcile LLM and deterministic overall scores according to config thresholds.

**Kind**: global function
**Returns**: <code>Object</code> - Reconciled score and preference source.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>object</code> |  | Reconciliation inputs. |
| [options.llmOverall] | <code>number</code> \| <code>null</code> |  | LLM overall score. |
| [options.deterministicScore] | <code>object</code> \| <code>null</code> |  | Deterministic score payload. |
| [options.config] | <code>object</code> | <code>{}</code> | Effective config. |
| [options.logger] | <code>object</code> |  | Logger for warnings. |

**Example**
```js
const result = reconcileScoreOverall({ llmOverall: 20, deterministicScore: { overall: 60 } });
```
<a name="scoreMPS"></a>

## scoreMPS(options) ⇒ <code>Promise.&lt;Object&gt;</code>
Score meaning preservation between original and rewritten text.

**Kind**: global function
**Returns**: <code>Promise.&lt;Object&gt;</code> - MPS result.
**Throws**:

- <code>Error</code> When the operation is aborted.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | MPS options. |
| options.original | <code>string</code> | Original text. |
| options.rewritten | <code>string</code> | Rewritten text. |
| [options.apiKey] | <code>string</code> | Provider API key. |
| [options.baseURL] | <code>string</code> | Provider base URL. |
| [options.model] | <code>string</code> | Model id. |
| [options.deadline] | <code>number</code> | Absolute epoch-millisecond deadline. |
| [options.signal] | <code>AbortSignal</code> | External cancellation signal. |
| [options.callLLM] | <code>function</code> | Injectable LLM implementation. |
| [options.logger] | <code>object</code> | patina logger. |
| [options.now] | <code>function</code> | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> | Sleep helper for tests. |

**Example**
```js
const mps = await scoreMPS({ original: 'A', rewritten: 'A', callLLM: async () => '{"mps":100,"anchors":[]}' });
```
<a name="interpretScore"></a>

## interpretScore(score) ⇒ <code>string</code>
Convert a numeric AI-likeness score to a human-readable band.

**Kind**: global function
**Returns**: <code>string</code> - Interpretation band.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| score | <code>number</code> | AI-likeness score from 0 to 100. |

**Example**
```js
const label = interpretScore(28); // mostly human
```
<a name="lengthRatioPoints"></a>

## lengthRatioPoints(original, rewritten) ⇒ <code>number</code>
Score rewritten length ratio on the 0-3 fidelity scale.

**Kind**: global function
**Returns**: <code>number</code> - Length-ratio points from 0 to 3.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| original | <code>string</code> | Original text. |
| rewritten | <code>string</code> | Rewritten text. |

**Example**
```js
const points = lengthRatioPoints('abcd', 'abcde');
```
<a name="scoreFidelity"></a>

## scoreFidelity(options) ⇒ <code>Promise.&lt;Object&gt;</code>
Score fidelity between original and rewritten text using length plus LLM criteria.

**Kind**: global function
**Returns**: <code>Promise.&lt;Object&gt;</code> - Fidelity result.
**Throws**:

- <code>Error</code> When the operation is aborted.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Fidelity options. |
| options.original | <code>string</code> | Original text. |
| options.rewritten | <code>string</code> | Rewritten text. |
| [options.apiKey] | <code>string</code> | Provider API key. |
| [options.baseURL] | <code>string</code> | Provider base URL. |
| [options.model] | <code>string</code> | Model id. |
| [options.deadline] | <code>number</code> | Absolute epoch-millisecond deadline. |
| [options.signal] | <code>AbortSignal</code> | External cancellation signal. |
| [options.callLLM] | <code>function</code> | Injectable LLM implementation. |
| [options.logger] | <code>object</code> | patina logger. |
| [options.now] | <code>function</code> | Clock returning epoch milliseconds. |
| [options.sleep] | <code>function</code> | Sleep helper for tests. |

**Example**
```js
const fidelity = await scoreFidelity({ original: 'A', rewritten: 'A', callLLM: async () => '{"criteria":{"meaning":3,"tone":3,"no_unintended_additions":3}}' });
```
<a name="clamp03"></a>

## clamp03(v) ⇒ <code>number</code>
Clamp and round a value into the inclusive 0-3 scoring range.

**Kind**: global function
**Returns**: <code>number</code> - Integer from 0 to 3.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| v | <code>number</code> \| <code>string</code> | Value to clamp. |

**Example**
```js
const value = clamp03(4.2); // 3
```
<a name="combinedScore"></a>

## combinedScore(options) ⇒ <code>number</code>
Combine AI-likeness, inverted fidelity, and optional deterministic score.

**Kind**: global function
**Returns**: <code>number</code> - Combined score, lower is better.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| options | <code>object</code> | Combined score inputs. |
| options.aiLikeness | <code>number</code> | AI-likeness score, lower is better. |
| options.fidelity | <code>number</code> | Fidelity score, higher is better. |
| [options.profile] | <code>string</code> | Profile name for configured weights. |
| [options.config] | <code>object</code> | Effective config. |
| [options.deterministicScore] | <code>number</code> \| <code>object</code> \| <code>null</code> | Optional deterministic score. |

**Example**
```js
const score = combinedScore({ aiLikeness: 20, fidelity: 90, profile: 'default', config: {} });
```
<a name="validateProfileName"></a>

## validateProfileName(name) ⇒ <code>void</code>
Validate a profile name before resolving profiles/{name}.md.

**Kind**: global function
**Throws**:

- <code>PatinaCliError</code> When the name is empty, non-string, or contains unsafe characters.


| Param | Type | Description |
| --- | --- | --- |
| name | <code>string</code> | Profile name supplied by CLI or config. |

**Example**
```js
validateProfileName('default');
```
<a name="isLoopbackHost"></a>

## isLoopbackHost(hostname) ⇒ <code>boolean</code>
Check whether a hostname is localhost or loopback.

**Kind**: global function
**Returns**: <code>boolean</code> - True for localhost, 127/8, or ::1.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| hostname | <code>string</code> | Hostname from a URL. |

**Example**
```js
const local = isLoopbackHost('127.0.0.1');
```
<a name="isPrivateOrSpecialIP"></a>

## isPrivateOrSpecialIP(hostname) ⇒ <code>boolean</code>
Detect literal private, reserved, link-local, metadata, or multicast IP hosts.

**Kind**: global function
**Returns**: <code>boolean</code> - True when the literal IP is private or special-use.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| hostname | <code>string</code> | Hostname or bracketed IPv6 literal. |

**Example**
```js
const blocked = isPrivateOrSpecialIP('169.254.169.254');
```
<a name="validateBaseURL"></a>

## validateBaseURL(baseURL, [options]) ⇒ <code>void</code>
Validate a provider base URL before sending prompts and bearer tokens.

**Kind**: global function
**Throws**:

- <code>PatinaCliError</code> When the URL is invalid, unsupported, insecure, or private without opt-in.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| baseURL | <code>string</code> |  | URL to validate. |
| [options] | <code>object</code> |  | Validation opt-ins. |
| [options.allowInsecure] | <code>boolean</code> | <code>false</code> | Allow non-loopback HTTP. |
| [options.allowPrivate] | <code>boolean</code> | <code>false</code> | Allow private/reserved literal IPs. |

**Example**
```js
validateBaseURL('https://api.openai.com/v1');
```
<a name="shouldAllowInsecureBaseURL"></a>

## shouldAllowInsecureBaseURL([parsed]) ⇒ <code>boolean</code>
Read CLI/env opt-in for non-loopback HTTP base URLs.

**Kind**: global function
**Returns**: <code>boolean</code> - True when insecure base URLs are explicitly allowed.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [parsed] | <code>object</code> | Parsed CLI options. |

**Example**
```js
const allowed = shouldAllowInsecureBaseURL({ allowInsecureBaseURL: true });
```
<a name="applyInsecureBaseURLOptIn"></a>

## applyInsecureBaseURLOptIn([parsed]) ⇒ <code>void</code>
Persist CLI insecure-base-url opt-in into process.env for downstream calls.

**Kind**: global function
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [parsed] | <code>object</code> | Parsed CLI options. |

**Example**
```js
applyInsecureBaseURLOptIn({ allowInsecureBaseURL: true });
```
<a name="shouldAllowPrivateBaseURL"></a>

## shouldAllowPrivateBaseURL([parsed]) ⇒ <code>boolean</code>
Read CLI/env opt-in for private or reserved literal IP base URLs.

**Kind**: global function
**Returns**: <code>boolean</code> - True when private base URLs are explicitly allowed.
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [parsed] | <code>object</code> | Parsed CLI options. |

**Example**
```js
const allowed = shouldAllowPrivateBaseURL({ allowPrivateBaseURL: true });
```
<a name="applyPrivateBaseURLOptIn"></a>

## applyPrivateBaseURLOptIn([parsed]) ⇒ <code>void</code>
Persist CLI private-base-url opt-in into process.env for downstream calls.

**Kind**: global function
**Throws**:

- <code>Error</code> Propagates validation, filesystem, network, or dependency failures when the underlying operation cannot complete.


| Param | Type | Description |
| --- | --- | --- |
| [parsed] | <code>object</code> | Parsed CLI options. |

**Example**
```js
applyPrivateBaseURLOptIn({ allowPrivateBaseURL: true });
```
