0.5.0 is the axis separation `de09711` built: `Risk` (assessment) alongside `Disposition` (action), `Policy.action_map` as the supported override, and the fail-closed path pinned to both axes. Additive and measured to be so — 717 passing with no test changed, matrix 128/128 with 6/6 documented gaps, the `PRESET_USER_UPLOAD` grading table unchanged row by row. Plus the field FP measurement (`d1bff60`) and the 0.3.3 behaviour-change correction (`d3d0928`). WHY THIS COMMIT TOUCHES EIGHT FILES AND 0.4.0's TOUCHED THREE 0.4.0's release commit updated CHANGELOG, pyproject.toml and __init__.py, and deferred README deliberately: the install block should not name a tag before a clean-venv install had proven it resolved. Sound reasoning, and the proof step never ran — so tag v0.4.0 permanently advertises v0.3.4. The tag is not moved. The ordering is. Sweeping every tracked file for a version claim, instead of ticking the four surfaces the checklist named, found five more that no release had ever touched: SECURITY.md "pre-1.0 (0.2.x)" — the one with a consequence for an outsider: it named a support window two minor lines behind the code. README.md "**Status:** v0.3" — the front page, stale since 0.4.0. docs/BRIEF.md "v0.2 (alpha)" — stale since 0.3.0. CLAUDE.md "v0.2 (alpha)" and "12 moduler" where src/ has 15. docs/ADOPTION-BRIEF "703 passing" where the suite is at 717. Measurement provenance is deliberately left alone: "New in v0.4.0", "verified identical on 0.2.0 and 0.3.1", "measured against the v0.3.1 tag", every "post-0.4.0 tree" in LIMITATIONS. Bumping those falsifies the record instead of updating it, which is why this cannot be a sed sweep — the surfaces have to be sorted into current-state and provenance before a single edit. Found because llm-ingestion-okf took our report of this defect class as a hypothesis about their own repo, measured it, found a worse instance on their public front page, and sent back the generalization: writing down a trap is not the same as applying it. VERIFIED BEFORE COMMITTING, NOT AFTER 717 passed; coverage 128/128 recall, 6/6 documented gaps hold docs/LIMITATIONS.md: 33 items, README says 33 fp-sweep reproduced all three published numbers exactly on the bumped tree — vendor-harvest 98/185 (53.0%), generated-notes 88/547 (16.1%), reference-corpus 133/389 (34.2%) — and self-docs runs clean, so the untested script survived the bump it imports names from forge description: 178 codepoints, under the 180 cap no tracked file carries a stale current-state version claim Still to prove before the tag: a clean-venv install from this commit's sha, and `git show <sha>` over the README. The install proves the package builds; only the grep proves the text the tag will carry is right. That second check is the one the old ordering could not perform, because by then the tag existed.
362 lines
22 KiB
Markdown
362 lines
22 KiB
Markdown
# Brief: `llm-ingestion-pipeline-security`
|
|
|
|
**A reusable, minimal, dependency-light defensive layer for LLM *ingestion*
|
|
pipelines — the write-time siblings of query-time chatbot guardrails.**
|
|
|
|
Status: implemented — v0.5 (alpha). This document defines what the repo contains
|
|
and why; the stdlib-only core is built and tested (see `README.md` for usage and
|
|
`docs/PLAN.md` for the build order).
|
|
|
|
---
|
|
|
|
## 1. One-line purpose
|
|
|
|
Give any pipeline that runs untrusted content through a large language model and
|
|
then **persists the result into a downstream-consumed artifact** (RAG corpus,
|
|
knowledge base, wiki, embeddings store) a small, framework-agnostic library that
|
|
packages the *architectural contract* for doing it safely: sanitize → fence →
|
|
tool-less quarantined transform → capability isolation → scan output before
|
|
commit → fail-secure.
|
|
|
|
## 2. The problem, stated precisely
|
|
|
|
The mature tooling for prompt injection is **query-time**: it sits between a user
|
|
(or an agent) and a model, at inference, on live traffic. Ingestion is a
|
|
different shape and is underserved:
|
|
|
|
- **Direction.** The danger flows from *content* (documents, changelogs, scraped
|
|
web pages, user uploads, tickets) through an LLM *enrichment/summarization/
|
|
extraction/classification* step, into a **persisted artifact** that other
|
|
systems and agents later read.
|
|
- **Two distinct failure modes**, only the first of which query-time guardrails
|
|
address:
|
|
1. **Injection steers the enrichment step** — untrusted content contains
|
|
instructions that hijack the summarizer/extractor.
|
|
2. **Poisoned content is published** — the artifact itself becomes the attack.
|
|
A verbatim-quoted payload, or an LLM-emitted instruction, lands in the
|
|
knowledge base and later poisons a *downstream* agent's context. This is
|
|
RAG/memory poisoning committed at *write* time, and a query-time guardrail
|
|
on the downstream reader never sees where it came from.
|
|
- **Non-interactive, unattended.** Ingestion typically runs headless on a
|
|
schedule. There is no human in the loop to notice a weird answer. Failure
|
|
discipline (fail-secure, alerting, no silent verbatim fallback under attack)
|
|
matters more here than in a chat UI.
|
|
|
|
## 3. Prior art and honest positioning
|
|
|
|
Injection *detection* is a crowded space. This repo must not pretend otherwise.
|
|
|
|
| Tool | Orientation |
|
|
|------|-------------|
|
|
| LLM Guard, Guardrails AI, NeMo Guardrails | Query-time I/O guardrails / dialogue policy |
|
|
| Rebuff | Self-hardening query-time detector (vector store of past attacks) |
|
|
| Vigil, Lakera Guard, Vijil | Query-time injection classifiers / detection servers |
|
|
| LlamaFirewall (Meta) | Agent guardrail framework (I/O, tool calls) |
|
|
| Resk | Python guardrail lib for LLM API calls |
|
|
| CleanBase, DataFilter (research) | Detecting/cleaning malicious docs in RAG DBs |
|
|
|
|
The gap this repo fills is **not** "no one detects injection." It is:
|
|
|
|
> A small **library** (not a hosted service, not a fine-tuned model) that
|
|
> packages the **write-time ingestion contract** — quarantined tool-less
|
|
> transform, per-stage capability isolation, output-scan-before-persist,
|
|
> fail-secure disposition — as composable, framework-agnostic, minimal-dependency
|
|
> code, with corpus-aware false-positive control.
|
|
|
|
**Necessary honesty (verified, see §11):** 2025 research shows character-level
|
|
and adversarial-ML evasion defeats most pattern- and classifier-based detectors
|
|
while keeping the payload legible to the target model. Therefore the value of
|
|
this library is **architecture and defense-in-depth**, not a detector that
|
|
"solves" injection. The lexicon is one WARN-class layer; the *contract* (a
|
|
tool-less call that cannot act on a successful injection, credentials the
|
|
hijacked step never holds, output scanned before it is trusted) is the load-
|
|
bearing part. The brief must lead with the contract, not the regex.
|
|
|
|
## 4. Design principles
|
|
|
|
1. **Minimal dependencies.** Stdlib-first core. Optional pluggable detectors
|
|
(an embedding classifier, an LLM-judge) live behind extras, never in the core
|
|
path. A pipeline should be able to adopt the core with zero new runtime deps.
|
|
2. **Framework-agnostic.** Works with any SDK (Anthropic, OpenAI, local). The
|
|
library never makes the model call; it hardens the call the pipeline makes.
|
|
3. **Pure functions.** Detection is `text -> findings`. No network, no telemetry,
|
|
no global state. Portable, testable, auditable.
|
|
4. **Disposition belongs to the caller.** The library reports; the pipeline
|
|
decides WARN vs quarantine-review vs fail-secure-halt. Defaults are provided,
|
|
but blocking is never imposed — see principle 5.
|
|
5. **Corpus-aware false-positive control.** A corpus that *legitimately discusses*
|
|
prompt injection (security docs, changelogs, a wiki about AI safety) will trip
|
|
any broad lexicon. The library must make WARN-not-block the easy default and
|
|
hard-fail an explicit, calibrated opt-in. Silent over-blocking of legitimate
|
|
content is a failure mode, not a safe default.
|
|
6. **Fail-secure under compound signals.** Injection-scan hit *and* a transform
|
|
failure is treated as a probable forced-fallback attack: halt + alert, never
|
|
an auto-committed verbatim entry. The same default applies when the output
|
|
scanner itself is **unavailable or errors** (a missing/unresolvable detector
|
|
dependency, a scanner exception): treat an un-scannable artifact as a BLOCK —
|
|
never persist it unscanned. Fail closed, not open. (Verified in the first
|
|
output-side implementation, 2026-07-04: an unresolvable detector is turned into
|
|
a hard-fail, not a silent pass.)
|
|
7. **Disposition scales with source trust.** The *same* lexicon should not carry
|
|
the *same* disposition for every source. A pinned, reputable, single-author
|
|
source (an official changelog) warrants **WARN** — false positives from
|
|
legitimate security vocabulary dominate the real signal. An open,
|
|
user-generated source (a community Q&A forum, scraped web) warrants
|
|
**QUARANTINE_REVIEW or hard-fail on high-severity hits** — a random
|
|
contributor emitting a spoofed `<system>` block is not "legitimately
|
|
discussing injection," and the cost of over-blocking one forum post is far
|
|
lower than publishing a poisoned one. Source trust level is therefore a
|
|
first-class input to the disposition policy, not a global constant.
|
|
|
|
**Trust also tiers *within* a document, not only across sources** (verified in
|
|
the first output-side implementation, 2026-07-04). A fenced code sample or a
|
|
localized (non-English) string inside an otherwise-authoritative doc is the
|
|
low-trust surface *even when the document's source is reputable* — a spoofed
|
|
`<system>` block or a base64 blob in a code sample is far likelier a real
|
|
payload than a false positive, whereas the same lexicon hit in authored,
|
|
en-locale prose is likelier a doc legitimately discussing the pattern. So the
|
|
*same* hit hard-fails inside a code block / localized string but WARNs in
|
|
authored prose. Intra-document provenance (in-code-fence, non-en locale) is a
|
|
first-class disposition input alongside source-level trust. Invisible carriers
|
|
(zero-width / bidi / Unicode-tag) and critical injection are the exception:
|
|
they have no legitimate place in a reference file and block in any tier.
|
|
|
|
## 5. Proposed module layout
|
|
|
|
```
|
|
src/llm_ingest_security/
|
|
sanitize/ Carrier stripping: invisible chars (Unicode Tags, zero-width,
|
|
bidi), HTML comments, data: URIs. Byte-identical on clean input;
|
|
removes only, never rewrites. Per-class counts for a WARN gate.
|
|
fence/ Spotlighting helpers: wrap untrusted input in markers, and strip
|
|
the markers FROM the input first so it cannot break out of its
|
|
own fence.
|
|
lexicon/ Semantic injection patterns as DATA (regex + label + severity),
|
|
tiered CRITICAL/HIGH/MEDIUM: override, spoofed headers/tags,
|
|
identity redefinition, config attacks, NL-indirection
|
|
(fetch-and-execute, send-to-external, read-dotfiles,
|
|
extract-and-exfiltrate), sub-agent spawn, leetspeak/homoglyph,
|
|
multi-language. Curated, versioned, re-syncable.
|
|
entropy/ base64/hex blob detection for smuggled encoded instructions or
|
|
encoded exfil (complements secret-pattern scanning).
|
|
contract/ The quarantine asserters — the differentiator:
|
|
- assert the model request carries NO tools
|
|
- assert per-stage credential allowlist (the enrichment step
|
|
sees exactly the one key it needs, and none of the publish
|
|
credentials)
|
|
- capability-isolation helpers (env scoping)
|
|
output/ Output-side scanner: run the lexicon + entropy over the model's
|
|
OUTPUT (summary, verbatim quotes, extracted fields) BEFORE the
|
|
artifact is persisted. This is the RAG-poisoning gate.
|
|
disposition/ Policy object: WARN | QUARANTINE_REVIEW | FAIL_SECURE per gate,
|
|
plus the compound-signal fail-secure rule.
|
|
report/ Structured findings: class, count, severity, offset, source
|
|
(input|output), disposition.
|
|
```
|
|
|
|
## 6. The reusable contract (adopt-this checklist)
|
|
|
|
The actual product is this checklist, encoded as code a pipeline wires in order:
|
|
|
|
1. **Sanitize before fence.** Strip carrier classes from untrusted input first.
|
|
2. **Fence untrusted input.** Spotlight-mark it; strip markers from the payload.
|
|
3. **Tool-less transform.** Call the model with zero tools. A successful
|
|
injection then has nothing to act with.
|
|
4. **Per-stage capability isolation.** The enrichment stage holds only the model
|
|
key; the publish stage holds only the publish credential; no stage holds both.
|
|
5. **Treat output as data.** Parse to a frozen schema; reject on structural
|
|
violation. The output never reaches a shell, git, or a filesystem path.
|
|
6. **Scan output before persist.** Run the lexicon + entropy over the emitted
|
|
text. Verbatim-carried payloads and model-emitted instructions are caught here.
|
|
7. **Fail-secure on compound signals.** Injection hit + transform failure = halt
|
|
+ alert, never a silent verbatim commit.
|
|
8. **Minimal alert payloads.** Alert with a gate code + run ID, never content.
|
|
Treat the alert channel/topic as a secret.
|
|
|
|
## 7. Non-goals
|
|
|
|
- **Not** a query-time chatbot / agent guardrail (that space is served).
|
|
- **Not** a fine-tuned model or a required ML classifier — deterministic core;
|
|
ML detectors are optional, pluggable extras.
|
|
- **Not** a hosted service or SaaS.
|
|
- **Not** a silver bullet — explicitly a defense-in-depth layer whose lexicon is
|
|
bypassable in isolation; the contract is what carries the security.
|
|
|
|
## 8. Language, packaging, licensing
|
|
|
|
- **Python first** — most ingestion pipelines are Python. Stdlib-only core;
|
|
`pyproject.toml` with optional extras (`[ml]`, `[judge]`).
|
|
- Framework-agnostic public API; no SDK imported by the core.
|
|
- A Node/TypeScript port is a plausible follow-on (a shared JSON lexicon as the
|
|
single source of truth across both).
|
|
- Permissive license (MIT or Apache-2.0) so it is droppable into any pipeline.
|
|
|
|
## 9. Test strategy
|
|
|
|
- **Adversarial corpus.** A seeded set of payloads (one per lexicon class,
|
|
including obfuscated and multi-language variants); measure and report *recall*.
|
|
- **False-positive corpus.** Real content that legitimately discusses injection
|
|
(security docs, changelogs); assert the default disposition is WARN, not block,
|
|
and that hard-fail is an explicit opt-in.
|
|
- **Sanitizer invariant.** Clean input returns byte-identical with an all-zero
|
|
report; the sanitizer only removes.
|
|
- **Contract asserters.** A tool-carrying request and a credential-leaking stage
|
|
env both raise; the happy path passes.
|
|
- **No network in any test.**
|
|
|
|
## 10. Threat-model grounding
|
|
|
|
- OWASP LLM Top 10: **LLM01 Prompt Injection**, output-handling, and the RAG /
|
|
knowledge-poisoning vectors.
|
|
- Google DeepMind "AI Agent Traps" (Franklin et al., 2025): Latent Memory
|
|
Poisoning and RAG Knowledge Poisoning map directly onto the write-time artifact.
|
|
- Research anchors: CleanBase (malicious docs in RAG DBs), DataFilter, and the
|
|
2025 guardrail-evasion literature that motivates the defense-in-depth framing.
|
|
|
|
## 11. Verification log (prior-art claims + sources)
|
|
|
|
Per the operator's verification duty — key claims in this brief and where they
|
|
are grounded:
|
|
|
|
- *Injection detection is crowded and query-time oriented* — LLM Guard, NeMo
|
|
Guardrails, Guardrails AI, Rebuff, Vigil, Vijil, LlamaFirewall, Resk, verified
|
|
via the 2026 guardrails comparison and tool docs.
|
|
- https://dev.to/agdex_ai/best-ai-agent-security-guardrails-tools-in-2026-llm-guard-vs-nemo-vs-guardrails-ai-5e5d
|
|
- *Pattern/classifier detection alone is bypassable (defense-in-depth framing)* —
|
|
"Bypassing LLM Guardrails: An Empirical Analysis of Evasion Attacks", arXiv
|
|
2504.11168 (character injection defeats most guardrails).
|
|
- https://arxiv.org/abs/2504.11168
|
|
- *Write-time RAG-DB poisoning is a researched but under-tooled vector* —
|
|
CleanBase (detecting malicious documents in RAG knowledge databases).
|
|
- https://arxiv.org/pdf/2605.00460
|
|
- *Multi-agent output-guard-before-release architecture exists in research* —
|
|
"A Multi-Agent LLM Defense Pipeline Against Prompt Injection Attacks",
|
|
arXiv 2509.14285.
|
|
- https://arxiv.org/abs/2509.14285
|
|
- *LlamaFirewall as an open-source guardrail reference* — arXiv 2505.03574.
|
|
- https://arxiv.org/pdf/2505.03574
|
|
|
|
**Novelty claim — verified (focused, adversarial PyPI + GitHub survey, 2026-07-15).**
|
|
The claim was re-checked by searching for the library that would *disprove* it, not
|
|
confirm it. It survives, but only in the **composite-contract** form below — never as
|
|
an absolute "the only" / "the first" claim. Characterizations are from PyPI metadata,
|
|
project READMEs, and author write-ups, not a line-by-line code audit.
|
|
|
|
- **`aig-guardian`** — PyPI v2.0.0, Apache-2.0, real repo (`killertcell428/ai-guardian`),
|
|
actively developed. Shares this library's *packaging philosophy* (zero-dep core +
|
|
`[fastapi]/[langchain]/[openai]` extras). Does **not** disprove the contract: it is
|
|
**query-time** middleware (`check_input`/`check_output`/`check_context`; its RAG
|
|
feature scans retrieved chunks as they enter the prompt), with no write-time
|
|
quarantine → scan-before-persist → fail-secure ingestion stage. Blurs the
|
|
"minimal-dep library" differentiator, not the contract.
|
|
- https://pypi.org/project/aig-guardian/
|
|
- **`GuardLLM`** — PyPI/GitHub v1.1.0, MIT, minimal-dep (only hard dep
|
|
`beautifulsoup4`). The nearest neighbour. Hardens *untrusted content at runtime*
|
|
(wraps inbound web/tool/MCP/email content before the LLM reads it; provenance +
|
|
outbound DLP). Does **not** package the write-time contract: no scan-before-persist
|
|
stage, no per-stage *capability* isolation, no named fail-secure disposition.
|
|
- https://github.com/mhcoen/guardllm
|
|
- **`ipi-scanner`** — PyPI v0.1.0, *ingestion-time* single-stage detector on paper,
|
|
but an **orphaned placeholder**: its metadata points at the literal template repo
|
|
`github.com/username/ipi-scanner` (404) and the license field is empty. Recorded for
|
|
honesty, not as prior art — unconfirmable, and even at face value a verdict-only
|
|
detector, not the contract.
|
|
- https://pypi.org/project/ipi-scanner/
|
|
- **Query-time incumbents** (LLM Guard, NeMo Guardrails, Guardrails AI, Rebuff, Vigil,
|
|
LlamaFirewall, Resk-LLM) — all sit between a user and a model at query time; none
|
|
address the write-time ingestion path (tracked in the rows above).
|
|
|
|
**Surviving, defensible form (this is what the README may claim):** existing OSS
|
|
tools are either single-stage *detectors* (emit a risk verdict, leave quarantine,
|
|
capability isolation, scan-before-persist, and fail-secure disposition to the
|
|
integrator) or runtime content-hardening; **no library packages the full four-part
|
|
*write-time ingestion* contract (quarantine → per-stage capability isolation →
|
|
scan-before-persist → fail-secure disposition) as composable minimal-dependency
|
|
code.** The nearest neighbour, GuardLLM, hardens content at runtime but has no
|
|
persist stage. Scoped, not absolute — and re-runnable: repeat the survey (search
|
|
"RAG ingestion security", "write-time / ingestion-time prompt injection", "ingest
|
|
guard") and confirm no new candidate covers all four parts together before making
|
|
the claim again.
|
|
|
|
## 12. Reference implementation and target consumers
|
|
|
|
The contract in §6 is not hypothetical — it is extracted from a working pipeline:
|
|
the `claude-code-llm-wiki` Stage B enrichment path (`tools/wiki_ingest/`),
|
|
which already implements sanitize + spotlight-fence + tool-less quarantined SDK
|
|
call + per-stage credential isolation + schema-validated output + fail-secure
|
|
`ForcedFallbackHalt`. That pipeline is the reference implementation for the *full
|
|
contract* (tool-less transform, credential isolation, fail-secure). The semantic
|
|
lexicon seed is the `injection-patterns.mjs` table from the `llm-security` plugin
|
|
(a pure regex+label+severity dataset, portable as data).
|
|
|
|
**Integration lesson (verified 2026-07-04) — consume the lexicon as a pure
|
|
function, not via the scanner CLI.** The `llm-security` orchestrator CLI
|
|
(`llm-security scan`) is repo/directory-oriented and, empirically, does **not**
|
|
apply the injection lexicon to arbitrary Markdown prose, nor does its
|
|
entropy-scanner flag a base64 blob inside a fenced code block — a full deep-scan
|
|
over three seeded fixtures caught only the invisible-Unicode class. The load-
|
|
bearing reuse seam is therefore the **importable pure primitives**
|
|
(`scanForInjection(text)` from `injection-patterns.mjs`; `isBase64Like` /
|
|
`shannonEntropy` from `string-utils.mjs`; the `unicode-scanner` module), driven
|
|
per line/region so the consumer controls provenance tiering. This library should
|
|
ship the lexicon **as data** and detection **as pure `text -> findings`
|
|
functions** (design principle 3) so no consumer has to shell out to an
|
|
orchestrator that under-covers its content type.
|
|
|
|
**Target consumers (the reason the library exists):**
|
|
|
|
1. **`claude-code-llm-wiki`** — low-untrust source (a pinned, reputable
|
|
Anthropic changelog). Here the contract is *defense-in-depth hygiene*; the
|
|
architectural controls already close the severe outcomes, and the lexicon runs
|
|
at WARN. This consumer is *retrofitting* the output-side widening late (at its
|
|
A13), which is precisely the cost this library exists to avoid for the next one.
|
|
2. **`ms-ai-architect`** (the plugin in `ktg-plugin-marketplace`; there is **no**
|
|
separate "MS AI Security plugin" — repo/name reconciled 2026-07-04) — an
|
|
ingestion pipeline over **Microsoft Learn** content fetched via the
|
|
`microsoft-learn` MCP (`microsoft_docs_fetch` / `_search` /
|
|
`_code_sample_search`): authored, reviewed Learn docs **plus code samples and
|
|
localized strings**. **Correction (verified against the live command/agent code
|
|
2026-07-04):** the earlier characterization — that it is the *high-untrust* end
|
|
ingesting the open Microsoft Q&A forum (`learn.microsoft.com/answers`), MSDN
|
|
Forums and Stack Overflow — is **unverified and overstated**. The pipeline's
|
|
fetch surface is authored Learn docs + code samples; it does not ingest the open
|
|
Q&A forum as part of its flow. Its low-trust surface is therefore
|
|
**intra-document** (a fenced code sample or a localized string inside an
|
|
otherwise-authoritative doc), which is exactly why disposition must tier at the
|
|
*chunk* level (§4.7), not treat the whole consumer as globally high-untrust.
|
|
Even so the contract is **load-bearing, not hygiene** here: the KB is publicly
|
|
distributed and re-served as instruction-adjacent context to every downstream
|
|
agent session, so one poisoned reference file is a supply-chain compromise.
|
|
|
|
A working, tested implementation of the **output-scan-before-persist** gate (§6
|
|
step 6) plus **provenance-tiered disposition** (§4.7) now exists in this plugin
|
|
— "Layer B" of its ingestion security gate, wired as a sibling to the existing
|
|
create-guard at the single write chokepoint, with a fail-closed exit-code
|
|
contract (0 clean / 1 block / 2 warn). It is the **second reference
|
|
implementation** for this library — specifically for the *output side* (the
|
|
RAG-poisoning gate + disposition), complementing consumer 1's reference for the
|
|
*full contract* (tool-less transform + credential isolation). It consumes the
|
|
`llm-security` lexicon by **in-process import of the pure functions** (see the
|
|
integration lesson above), which is a concrete data point for open decision §13.3.
|
|
|
|
**Why day-1, not retrofit.** The load-bearing parts of the contract are
|
|
architectural — tool-less quarantine, per-stage credential isolation,
|
|
output-scan-before-persist, fail-secure disposition. These are cheap to design in
|
|
and expensive to bolt on after a pipeline exists (consumer 1 is proving that).
|
|
Adopting the library from day 1 means the *high-untrust* consumer (2) inherits a
|
|
correct, calibrated contract for free instead of discovering the gap in
|
|
production. The library's value is not this pipeline; it is every pipeline after
|
|
it whose input is less trustworthy than a pinned changelog.
|
|
|
|
## 13. Open decisions for the operator
|
|
|
|
1. **Name** — `llm-ingestion-pipeline-security` is descriptive but long; a
|
|
shorter package name (e.g. `ingestguard`) may be worth it before first publish.
|
|
2. **License** — MIT vs Apache-2.0.
|
|
3. **Relationship to `llm-security`** — sibling repos sharing one lexicon dataset
|
|
as the single source of truth, or fully independent? Avoid two drifting copies
|
|
of the pattern table.
|
|
4. **Publish target** — Forgejo (`git.fromaitochitta.com`), and whether a public
|
|
`open/` mirror. No GitHub per house policy.
|
|
5. **Python-only vs polyglot** from day one.
|
|
6. **Maintenance model** — solo fork-and-own (as `llm-security`), or open to PRs.
|