Semantic Systems / Language / Glyphs
Robust Automated Testing Strategy for IOTA Aligned Coding AI
Report summary
The right testing strategy for a coding AI built around the IOTA language-converter model is not “compare strings and hope.” The Protocol5 IOTA converter explicitly says it performs approximate public-symbol semantic conversion , not exact translation; it segments input, maps the visible expression
Key topics
- Semantic Systems / Language / Glyphs
- Semantic Systems
- Language
- Glyphs
- AI
- .NET
- SQL
- Python
- Runtime
Research provenance
For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.
Source availability: 102 citation markers in the source export have no recoverable source links. Those markers are omitted from this reader; any supplied bibliography and ordinary links remain. Check the original sources before relying on the cited claims.
This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.
Full report
On this page
Executive summary
The right testing strategy for a coding AI built around the IOTA language-converter model is not “compare strings and hope.” The Protocol5 IOTA converter explicitly says it performs approximate public-symbol semantic conversion, not exact translation; it segments input, maps the visible expression to concept evidence, ranks public Unicode output candidates, and treats the authoritative object as the relation among expression, concept, score, provenance, and public-symbol boundary rules. It also separates visible expression from inferred concept, warns that round trips can drift, and exposes evidence fields such as segment trace, vector evidence, ranking lanes, scores, and provenance. A robust strategy therefore has to test semantic preservation, evidence completeness, Unicode safety, ranking quality, and drift visibility, not just exact output equality.
For coding AI more broadly, execution-based correctness must dominate superficial proxy metrics. HumanEval established execution-based functional correctness and pass@k as core code-generation measures, while EvalPlus showed that weak tests can materially overestimate correctness and even mis-rank models. Repo-level suites such as SWE-bench, SWE-bench Verified, LiveCodeBench, and BigCodeBench then expose the harder reality: coding agents fail in ways that function-level suites alone miss, especially when tasks require multi-file edits, library use, self-repair, or longer-horizon reasoning.
The best practical design is an evidence-first, layered portfolio: deterministic contract tests for parser, schema, and Unicode invariants; unit and integration tests for conversion logic and registry lookups; system tests for end-to-end conversion and round trips; regression suites on a versioned golden corpus; adversarial, property-based, metamorphic, fuzzing, mutation, and differential tests for robustness; and benchmark lanes for function-level, repo-level, multilingual, and performance-sensitive tasks. That portfolio should run in CI/CD with machine-readable outputs, and it should continue in production through telemetry, alerting, and drift analysis.
A strong default stack is available from primary and official sources: pytest, JUnit 5, xUnit.net, or MSTest for core tests; Hypothesis or QuickCheck-style property tests; libFuzzer and OSS-Fuzz for coverage-guided fuzzing; Playwright for browser/system tests; k6 for benchmark and load tests; coverage.py or JaCoCo for coverage; PIT or mutmut for mutation testing; Tree-sitter and CodeQL for parse- and query-based static oracles; Snorkel for weak supervision and label generation; Great Expectations for test-data validation; DVC and MLflow for experiment and artifact tracking; GitHub Actions or GitLab CI for orchestration; and OpenTelemetry, Prometheus, Alertmanager, and MLflow Tracing for observability. For governance and security, SemVer, reproducible builds, SLSA provenance, in-toto attestations, NIST SSDF, NIST AI RMF, and OWASP’s LLM guidance fit naturally into the same system.
The single most important design choice is to give the coding AI an explicit, machine-readable test manifest. JustAnIota emphasizes “readable first, compact second,” canonicalization, validator-backed examples, and a three-layer record style from plain-language summary to technical summary to deep specification. A coding AI should receive the same structure: what success means, which commands to run, which outputs are blocking, which metrics are advisory, which corpus snapshot to use, and exactly how to interpret semantic drift or ambiguity. Without that contract, even a powerful coding model tends to optimize for the wrong surrogate objective.
IOTA aligned testing principles
The Protocol5 IOTA pages imply a very specific philosophy of testing. The converter is deliberately approximate, not lossless; the visible glyph or symbol is not meaning by itself; phrase-first segmentation matters; normalization and Unicode safety are first-class; and even in DatabaseOnly mode the system is expected to remain inspectable and return visible evidence. The public record around JustAnIota adds registries, canonicalization, validation, deterministic envelopes, and validator-backed examples. Those details turn directly into testing requirements.
A second, underappreciated implication is that a failing test must be explainable to an agent. The IOTA pages already expose Developer JSON, Evidence Workbench views, ranking-lane counts, segment trace, vector evidence, approximation status, and provenance. Your testing harness should mirror that: every failed test should emit a concise human summary and a structured JSON artifact that an agent can parse to localize the defect. This is exactly the sort of “know when it is working and how to do it” feedback loop that coding agents need.
IOTA specific invariants and the tests they imply
| Protocol invariant | What the protocol says | Blocking test pattern | Best oracle |
|---|---|---|---|
| Approximate, not exact | IOTA is approximate public-symbol conversion and does not attempt exact translation. | Do not require single exact-string gold outputs except in narrow deterministic seed smoke tests | Semantic oracle, top-k acceptance set, round-trip concept retention |
| Expression and concept are separate | The converter separates visible expression from inferred concept and ranks the relation under evidence. | Assert concept anchors, evidence, and ranking quality separately from rendered glyphs | Concept-ID oracle, evidence-completeness oracle |
| Phrase-first segmentation | Paragraphs become sentences; sentences become segments; longest stored segment should match before single-word fallback. | Regression tests for longest-match precedence and segment boundaries | Exact structural oracle over trace output |
| Public Unicode only | Assigned public Unicode/ISO 10646 symbols are required; private-use areas are prohibited. | Reject or quarantine any candidate using private-use characters in public mode | Unicode safety oracle |
| Normalization matters | NFC normalization is part of the logic layer and IOTA envelopes explicitly carry normalization. Unicode normalization exists to give equivalent text a unique binary representation. | Metamorphic tests over NFC-equivalent inputs | Normalization-invariance oracle |
| DatabaseOnly remains useful | DatabaseOnly uses stored vectors and public evidence, and after population it must still return a basic gist without live AI. | Differential tests across DatabaseOnly and Hybrid; offline smoke tests | Mode-consistency oracle |
| Evidence is mandatory | Responses expose approximation status, ranked candidates, ranking lanes, segment trace, vector preview, scores, and provenance. | Contract tests for required fields and non-empty evidence | Schema and completeness oracle |
| Drift must stay visible | Round trips can drift, and the returned gist is not proof that original meaning survived unchanged. | Round-trip tests that score retained, lost, added, and ambiguous concepts | Semantic-drift oracle |
A useful implementation pattern is to make the above invariants explicit in a repository-level manifest that both humans and coding agents can consume. This mirrors JustAnIota’s “readable first, compact second” posture and its three-layer communication model.
version: 1
goal:
plain_english: "Preserve concept evidence and public-symbol safety; exact glyph equality is secondary."
technical_summary:
primary_oracles: [build, unit, iota_contract, concept_accuracy, unicode_safety]
secondary_metrics: [codebleu, bleu, rouge]
commands:
fast: "./scripts/test-fast"
deep: "./scripts/test-deep"
release_gates:
evidence_completeness: 1.0
private_use_violations: 0
blocking_flakiness_max: 0.01
top1_concept_accuracy_min: 0.95
artifacts:
- junit.xml
- results.json
- traces.ndjson
- benchmark_report.json
Test portfolio and design patterns
A durable strategy uses many test types because each covers a different failure surface. Property-based testing is good at surfacing edge cases hidden from hand-written examples; metamorphic testing addresses the oracle problem by checking relations between outputs rather than single expected outputs; differential testing compares two or more comparable systems and flags divergences; coverage-guided fuzzers push parsers and runtime boundaries; mutation testing checks whether the suite actually detects realistic faults; and execution-based benchmarks reveal whether the code really works under a reference harness.
Test types comparison
| Test type | What it should verify | IOTA aligned examples | Typical cadence | Good tool choices | Anchor references |
|---|---|---|---|---|---|
| Unit | Small, deterministic local behavior | normalization helpers, segment splitter, candidate scorer, provenance formatter | every commit | pytest, JUnit 5, xUnit.net, MSTest | pytest fixtures and parametrization ; JUnit 5 ; xUnit.net ; MSTest |
| Integration | Interactions among parser, vector store, registry, validator, retriever | DatabaseOnly with seed registry; SQL-backed ranking; validator + converter agreement | every commit | same as unit framework plus containerized fixtures | IOTA public seed and SQL-backed paths |
| System | End-to-end behavior through full envelope, API, UI, and browser | English→IOTA conversion, round-trip English gist, evidence workbench rendering | every PR and nightly | Playwright | Playwright runs across Chromium, WebKit, Firefox, and mobile emulation. |
| Regression | Stability against known historical defects | replay fixed bugs, Unicode regressions, ranking-lane regressions | every PR | core test framework + golden corpus | IOTA emphasizes visible drift and seed-vs-SQL comparisons. |
| Adversarial | Security and robustness under malicious or pathological inputs | prompt injection text, bidi controls, zero-width joiners, confusables, overlong segments | nightly and release | custom corpus + static analysis + sandbox | OWASP LLM guidance and Unicode cautions. |
| Property-based | Invariants over wide input spaces | NFC invariance, synonym-preserving concept anchor stability, score monotonicity in obvious cases | every PR | Hypothesis, QuickCheck-style frameworks | Hypothesis docs ; QuickCheck |
| Fuzzing | Parser and runtime hardening via coverage-guided random input generation | malformed UTF-8, mixed scripts, surrogate-like edge cases, JSON envelope corruption | nightly/continuous | libFuzzer, OSS-Fuzz | libFuzzer and OSS-Fuzz |
| Metamorphic | Semantic relations where exact outputs are unavailable or undesirable | normalize(input) should preserve concept; paraphrase should preserve top concepts; phrase decomposition should not raise confidence spuriously | every PR | custom harness, often backed by property test engine | metamorphic testing survey |
| Differential | Agreement across implementations, modes, or baselines | DatabaseOnly vs Hybrid; seed vs SQL ranking; current main vs candidate branch | every PR and canary | custom harness + baseline artifacts | differential testing paper |
| Mutation | Whether tests kill realistic seeded faults | wrong score sort order, normalization removed, provenance omitted, polarity flipped | nightly | PIT, mutmut | PIT and mutmut docs |
| Benchmark suites | External realism and trend tracking | HumanEval, EvalPlus, SWE-bench Verified, LiveCodeBench, BigCodeBench, mHumanEval, MultiPL-E | nightly and release | dedicated benchmark harnesses | execution-based and repo-level benchmarks |
A useful design pattern for coding agents is staged gates. Keep PR-time suites fast and deterministic: build, syntax, unit, contract, property checks, and a small IOTA golden set. Move fuzzing, mutation, large benchmarks, and performance regressions to nightly or pre-release lanes. This is compatible with GitHub Actions, GitLab CI pipelines, and Jenkins pipelines, all of which treat CI/CD as code and support staged, triggered workflows.
The second crucial pattern is layered oracles. For a converter like IOTA, one oracle is never enough. An output can be structurally valid but semantically wrong; semantically plausible but missing provenance; or fully traceable but operationally too slow. Good test cases therefore capture at least one exact oracle, one semantic oracle, and one operational oracle. EvalPlus is a strong reminder that test insufficiency makes models look better than they are.
Oracles, labels, and synthetic data
Because IOTA does not promise exact translation, gold data should be stored as acceptance regions, not single strings. The gold record for each case should include the canonical input, the expected concept anchors or concept IDs, an acceptable top-k candidate set when multiple outputs are valid, required evidence fields, safety constraints, and a round-trip concept-retention expectation. That directly matches the protocol’s approximate status, ranking lanes, candidate traces, and drift disclosure.
The strongest ground truth is deterministic and executable. For code-generation tasks, use compilers, interpreters, unit tests, static analyzers, AST parsers, and reference implementations. Tree-sitter is useful because it can build syntax trees quickly across many languages and tolerate syntax errors; CodeQL is useful because it lets you query code as data and encode families of structural or security expectations, not just exact outputs. For IOTA-specific tests, the registry and validator become semantic authorities, while Unicode normalization and safety rules become structural authorities.
The protocol rules also point to a practical labeling pipeline: build the symbol atlas from public metadata such as UCD, CLDR, Unihan, and emoji data; generate embeddings from descriptor text, anchors, code-point evidence, and source provenance rather than raw code points alone; and persist dimensions, model, prompt profile, public source, and exclusion state. Those ingredients are exactly what make automated label generation and auditability possible.
Example IOTA oriented test cases and their oracles
| Test case | Input pair or condition | Expected behavior | Primary oracle |
|---|---|---|---|
| Normalization invariance | e\u0301xpression vs éxpression | same top concept, same safety result, same required evidence | UAX #15 NFC equivalence oracle |
| Phrase-first priority | "good help" where phrase and words both exist | phrase-level segment should be matched before word fallback | exact segment-trace oracle from protocol rules |
| Public-symbol safety | any public conversion result | no private-use characters in public mode | Unicode safety oracle from IOTA rules |
| Evidence completeness | any successful conversion | mode, approximation status, segment trace, ranking lanes, scores, provenance all present | contract oracle over response fields |
| Offline determinism | DatabaseOnly with seeded registry | must still produce basic gist and evidence without live AI | mode-consistency oracle |
| Round-trip drift visibility | English→IOTA→English | retained/lost/added/ambiguous concepts must be measurable and surfaced | semantic-drift oracle |
| Seed vs SQL comparison | same query against seed and SQL-backed corpora | differences should be explainable and bounded | differential oracle with tolerance bands |
| Confusable and bidi attack | mixed confusables, RTL marks, ZWJ, combining marks | must not crash, must not bypass safety checks, confidence should drop on ambiguity | adversarial Unicode safety oracle |
| Prompt injection resilience | natural-language attempt to change mode or suppress evidence | converter should treat it as input text, not as control | security oracle plus contract oracle |
| Unknown intent abstention | out-of-domain or unsupported input | low confidence, ambiguity warning, or explicit abstention rather than fabricated certainty | precision/recall on abstention class |
Automated labeling should start from those deterministic cores and then scale outward. Snorkel-style weak supervision is especially useful when there is no single exact answer but many high-signal heuristics: registry matches, validator outputs, Unicode metadata, phrase dictionaries, previous production traces, or developer-authored rules. Snorkel’s core idea is to let experts write labeling functions that are imperfect and correlated, then combine them into probabilistic labels. That fits IOTA well because the system itself is ranking under evidence rather than claiming exact bilingual truth.
Synthetic data generation should serve two purposes: increase coverage and create realistic failure pressure. For coding tasks, the most effective recipe is a mix of hand-authored goldens, AST-preserving program transformations, API-call and argument mutations, boundary-value expansion, and benchmark augmentation in the style of EvalPlus, which used automatic input generation and mutation-based strategies to expose incorrect code that original test suites missed. For IOTA specifically, generate Unicode perturbations, segmentation variants, synonym/paraphrase variants, multilingual prompt variants, and adversarial surface forms that preserve or selectively alter concept anchors.
Example harnesses and oracles
The first harness should be a strict contract oracle. It is the fastest blocker and the easiest for a coding agent to understand.
# Python-like pseudocode
REQUIRED_FIELDS = {
"mode",
"approximate_status",
"segment_trace",
"ranking_lanes",
"ranked_candidates",
"scores",
"provenance",
}
def assert_iota_contract(resp):
assert REQUIRED_FIELDS.issubset(resp.keys())
assert resp["approximate_status"] is True
assert len(resp["ranked_candidates"]) > 0
assert len(resp["ranking_lanes"]) > 0
assert len(resp["segment_trace"]) > 0
for cand in resp["ranked_candidates"]:
assert cand["unicode_safe"] is True
assert not contains_private_use(cand["text"])
assert cand["score"] >= 0.0
assert cand["provenance"]
That pattern is grounded in IOTA’s documented response fields, approximation labels, and public-symbol safety rules, plus Unicode normalization and safety requirements.
The second harness should be metamorphic and property-based, because many IOTA behaviors are relation-preserving rather than string-preserving.
# Python-like pseudocode using a Hypothesis-style property framework
@given(any_unicode_text())
def test_nfc_invariance(text):
a = convert(text, mode="database-only")
b = convert(normalize_nfc(text), mode="database-only")
assert top_concept(a) == top_concept(b)
assert required_concepts(a) == required_concepts(b)
assert a["unicode_safe"] == b["unicode_safe"]
def test_database_only_vs_hybrid(seed_case):
db = convert(seed_case.input, mode="database-only")
hy = convert(seed_case.input, mode="hybrid")
assert jaccard(concept_anchors(db), concept_anchors(hy)) >= 0.80
assert abs(top_score(db) - top_score(hy)) <= 0.15
This combines the protocol’s mode distinctions with metamorphic testing’s oracle-problem logic and Hypothesis-style wide input generation.
Metrics, thresholds, and benchmark suites
For a converter or coding agent that is approximation-heavy and evidence-driven, metrics must be hierarchical. Blocking metrics should measure structural correctness, functional correctness, concept fidelity, evidence integrity, safety, and stability. Secondary metrics such as BLEU, ROUGE, and CodeBLEU are still useful, but mostly for trend analysis, model comparison, and narrow subproblems like code-to-code or text-to-code similarity. The reason is simple: IOTA itself rejects exact translation as the primary claim, while CodeBLEU was proposed precisely because plain BLEU misses code syntax and semantics.
The thresholds below are recommended starting gates for production engineering. They are not universal laws; they should be tightened or relaxed based on how safety-critical the deployment is.
Metrics and recommended starting thresholds
| Metric family | Recommended starting gate | Why it matters | Anchor references |
|---|---|---|---|
| Build, parse, type, schema validity | 100% on blocking corpus | A coding agent that cannot produce buildable or parseable output is not “working” in any meaningful sense | execution-based evaluation emphasis |
| Functional correctness | No regressions on blocking regression set; target ≥98% on release-blocking goldens | compilation alone is not correctness | HumanEval and EvalPlus |
| Top-1 concept accuracy | ≥95% on curated semantic goldens | IOTA output is approximate, so the winning concept must be right even if glyph choice varies | IOTA expression/concept model |
| Top-3 concept recall | ≥99% on curated semantic goldens | ranking should keep the correct concept candidate near the top | ranking-oriented IOTA evidence |
| Evidence completeness | 100% for required fields | evidence is part of the product contract, not a nice-to-have | IOTA evidence fields |
| Unicode safety violations | 0 in public-symbol mode | private-use leaks or unsafe Unicode handling break protocol boundaries | IOTA rules and Unicode normalization/safety guidance |
| Precision and recall on abstain/unknown path | Precision ≥0.95, recall ≥0.90 | better to abstain cleanly than to fabricate certainty on unknowns | precision/recall tradeoff guidance |
| Round-trip concept retention | ≥95% required anchors retained on critical intents | IOTA warns that round trips drift; you need a measurable retention target | round-trip drift note |
| Branch coverage on core logic | ≥85% | branch coverage reveals missed decisions that statement coverage hides | coverage.py branch coverage |
| Mutation score on core logic | ≥70% to start, ≥85% for mature critical paths | coverage can look good while tests remain weak | PIT / mutmut mutation testing |
| BLEU and ROUGE | Track trend; do not use as sole release gate | lexical overlap is useful for drift analysis but weak for semantic acceptance in IOTA | BLEU and ROUGE originals; IOTA approximation boundary |
| CodeBLEU | Use for code-to-code or text-to-code trend tracking; relative regression budget ≤2–3 points | better aligned with code syntax and data flow than BLEU alone | CodeBLEU paper |
| p95 latency | ≤10% regression vs pinned baseline or explicit SLO | operational regressions matter even when correctness is stable | Prometheus and OTel observability guidance |
| Peak memory / CPU / cost | ≤10–20% regression vs baseline | prevents silent cost blowups from “working” changes | observability and tracing tools support this tracking |
| Flakiness | <1% for blocking tests; <0.1% for contract suite | agents cannot reason reliably over unstable feedback | CI-friendly structured reports and disciplined retries |
A benchmark portfolio should then cover different scales of difficulty and different problem formulations.
Benchmark suites worth including
| Benchmark | What it measures best | Why it belongs in the portfolio | Primary output metric | Source |
|---|---|---|---|---|
| HumanEval | function-level code synthesis | small, canonical execution-based sanity check | pass@k | |
| MBPP | short Python problems from NL descriptions | broader entry-level synthesis coverage than HumanEval | test pass rate / pass@k | |
| EvalPlus | robustness of function-level code generation under stronger tests | catches false positives hidden by weak test suites | pass@k under augmented tests | |
| APPS | harder natural-language-to-code problems | more realistic long-spec coding competence | pass rate | |
| BigCodeBench | function-level tasks with complex instructions and diverse library calls | excellent for API use and realistic library interactions | correctness / leaderboard score | |
| SWE-bench Verified | repo-level issue resolution on human-validated tasks | strongest public reliability benchmark for coding agents | % resolved | |
| LiveCodeBench | continuously refreshed, contamination-resistant coding eval | useful against benchmark staleness and overfitting | task accuracy across generation, execution, self-repair | |
| mHumanEval | multilingual NL prompts for code generation | needed if prompts are multilingual or locale-sensitive | pass rate / multilingual deltas | |
| MultiPL-E | many programming-language targets for translated code-generation benchmarks | needed if target programming languages are diverse | per-language pass rate | |
| SWE-bench Multimodal | visually grounded JavaScript/software issues | useful for front-end and visual debugging domains | % resolved |
The practical release model is to pin a small blocking subset from these suites and run the full batteries nightly or at release candidates. That keeps CI fast while preserving strong external validity.
CI/CD, monitoring, and remediation
A coding AI only learns effectively from test feedback if the pipeline is predictable, staged, and artifact-rich. GitHub Actions, GitLab CI/CD, and Jenkins all support pipeline-as-code workflows with triggered jobs, staged execution, and artifact handling. For an evidence-heavy system like IOTA, the pipeline should emit JUnit XML for CI status, JSON traces for agent consumption, and benchmark reports for trend analysis. Pytest can emit JUnit XML for integration servers, and JUnit itself is built for test tooling and ecosystem interoperability.
flowchart LR
A[AI proposes patch or converter change] --> B[Static gates parse lint type schema]
B --> C[Unit and contract tests]
C --> D[Property metamorphic differential tests]
D --> E[Fuzz and mutation lanes]
E --> F[Benchmarks IOTA goldens HumanEval EvalPlus SWE-bench Verified]
F --> G[Canary or shadow deployment]
G --> H[Telemetry traces metrics logs]
H --> I[Drift analysis and baseline update]
C --> X[Block merge on failure]
D --> X
E --> X
F --> X
H --> Y[Incident response and remediation]
A good default lane structure is: fast PR gates, deep nightly gates, and release-candidate gates.
| Pipeline lane | Trigger | Blocking | Typical contents |
|---|---|---|---|
| Fast | every PR and push | yes | build, lint, unit, contract, property, small semantic golden set |
| Deep | nightly and manual on demand | usually yes for main branch, no for PR | mutation, fuzzing, extended differential, full benchmark subset |
| Release | tags and release branches | yes | reproducibility checks, provenance attestations, canary analysis, security review |
Sample CI configuration snippets
A repository-agnostic GitHub Actions workflow can keep the commands stable for both humans and coding agents while letting the implementation underneath remain polyglot.
name: ci
on:
pull_request:
push:
branches: [main]
schedule:
- cron: "0 3 * * *"
jobs:
fast-gates:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up toolchain
run: ./scripts/setup-ci.sh
- name: Lint and static checks
run: ./scripts/lint.sh
- name: Unit and contract tests
run: ./scripts/test-fast.sh --junit reports/junit.xml --json reports/results.json
- name: Upload reports
uses: actions/upload-artifact@v4
with:
name: fast-reports
path: reports/
deep-evals:
if: github.event_name == 'schedule' || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 180
needs: [fast-gates]
steps:
- uses: actions/checkout@v4
- name: Set up toolchain
run: ./scripts/setup-ci.sh
- name: Property, metamorphic, and differential suites
run: ./scripts/test-deep.sh
- name: Fuzzing and mutation
run: ./scripts/test-robustness.sh
- name: Benchmarks
run: ./scripts/benchmark.sh --baseline main --fail-on-regression
- name: Publish benchmark artifacts
uses: actions/upload-artifact@v4
with:
name: deep-eval-reports
path: reports/
GitHub Actions is a natural fit here because it is explicitly designed to automate and customize CI/CD workflows in the repository.
A comparable GitLab configuration follows the same logic.
stages:
- lint
- test
- deep_eval
lint:
stage: lint
script:
- ./scripts/setup-ci.sh
- ./scripts/lint.sh
fast_tests:
stage: test
script:
- ./scripts/test-fast.sh --junit reports/junit.xml --json reports/results.json
artifacts:
when: always
paths:
- reports/
reports:
junit: reports/junit.xml
deep_eval:
stage: deep_eval
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- ./scripts/test-deep.sh
- ./scripts/test-robustness.sh
- ./scripts/benchmark.sh --baseline main --fail-on-regression
artifacts:
when: always
paths:
- reports/
GitLab pipelines are defined in .gitlab-ci.yml, support stage-based execution, and can run automatically on pushes, merge requests, schedules, or manual triggers.
Recommended tools and frameworks
| Capability | Strong default | Good alternatives | Why it is a good fit | Source |
|---|---|---|---|---|
| Core unit and integration tests | pytest | JUnit 5, xUnit.net, MSTest | mature fixtures, parametrization, CI integrations | |
| Property-based tests | Hypothesis | QuickCheck-style libraries in other languages | efficient edge-case discovery over invariants | |
| Fuzzing | libFuzzer | OSS-Fuzz for continuous large-scale integration | coverage-guided fuzzing, strong parser/runtime hardening | |
| Browser and system tests | Playwright | framework-native UI test tools | multi-browser, mobile emulation, isolation | |
| Performance and load | k6 | repo- or stack-specific profilers/load tools | tests as code, easy CI use | |
| Coverage | coverage.py | JaCoCo on JVM stacks | line and branch visibility | |
| Mutation | PIT | mutmut | reveals weak tests that coverage alone misses | |
| AST and parse oracles | Tree-sitter | compiler-native parsers | cross-language parsing and incremental analysis | |
| Static semantic and security oracles | CodeQL | language-native analyzers and lint packs | query families of defects, not just one exact output | |
| Weak supervision and labeling | Snorkel | custom rule engines | scalable programmatic labels from imperfect heuristics | |
| Data quality checks | Great Expectations | custom schema validators | makes test-data assumptions explicit | |
| Experiment and artifact tracking | MLflow | DVC for data-and-pipeline-first workflows | logs metrics, artifacts, traces, and runs | |
| LLM and agent evaluation orchestration | OpenAI Evals / simple-evals | Inspect | reusable eval harnesses and benchmark execution | |
| Telemetry and alerting | OpenTelemetry + Prometheus + Alertmanager | vendor-specific stacks on top | standardized traces, metrics, logs, alerts |
Once the code is deployed, instrument it aggressively. Prometheus guidance is blunt: instrument everything; every library, subsystem, and service should expose enough metrics to understand behavior. OpenTelemetry provides the cross-vendor trace, metrics, and logs model, plus semantic conventions that standardize names and attributes. MLflow Tracing adds LLM- and agent-oriented observability on top, while Alertmanager handles grouping, deduplication, routing, silencing, and inhibition for alerts.
Operational dashboards should at minimum track: build success rate, contract pass rate, concept accuracy, unknown rate, round-trip drift, top-k ranking quality, Unicode safety violations, p50/p95 latency, peak memory, cost per request, benchmark deltas, and flakiness. The JustAnIota envelope already includes unknown_rate, visible segment traces, ranking lanes, and result modes; those should flow directly into production telemetry and historical drift dashboards.
Failure taxonomy and remediation flow
| Failure class | Typical signal | Automated response | Human remediation playbook |
|---|---|---|---|
| Structural failure | parse/build/type/schema failure | block merge immediately | inspect compiler/parser output; bisect recent changes; add regression test |
| Semantic regression | top concept wrong, concept retention drop, benchmark regression | fail PR or canary; compare against baseline branch | inspect traces and evidence deltas; review changed prompts/embeddings/registry |
| Evidence regression | missing segment trace, provenance, ranking lanes, approximation label | block release even if output “looks okay” | restore serialization contract; add contract test for missing field |
| Unicode safety violation | private-use character leak, normalization mismatch, bidi handling bug | quarantine build; notify security and i18n owners | reproduce with Unicode corpus; update normalization/safety rules |
| Performance regression | p95 latency or memory jump | keep build green only in non-blocking lane if user-approved; otherwise fail | profile hotspots; compare vector search and parser changes |
| Security sandbox issue | unexpected network access, file write, unsafe execution | hard fail and isolate environment | inspect sandbox policy, secrets exposure, dependency changes |
| Flaky or infra failure | inconsistent reruns | quarantine test, do not silently ignore | stabilize fixture, seed, clock, network, and environment assumptions |
flowchart TD
A[Alert or CI failure] --> B{Classify}
B --> C[Structural]
B --> D[Semantic or ranking]
B --> E[Unicode or safety]
B --> F[Performance or cost]
B --> G[Flake or infra]
C --> H[Block merge or rollback]
D --> I[Compare against baseline and traces]
E --> J[Quarantine build and run Unicode corpus]
F --> K[Profile and compare benchmark artifacts]
G --> L[Quarantine test and rerun with fixed seed]
H --> M[Patch plus regression test]
I --> M
J --> M
K --> M
L --> M
M --> N[Re-run fast and deep gates]
Governance, reproducibility, and security
A testing system is only trustworthy if it is versioned and reproducible. Public interfaces, schemas, and machine-readable test contracts should follow Semantic Versioning so that agents can reason about compatibility; a released version must not be modified in place. Data sets, registries, benchmark snapshots, and goldens should be versioned separately from code, with immutable tags and explicit compatibility metadata. DVC is well suited to versioning data, models, and experiments alongside Git, while MLflow records run metadata, parameters, metrics, and artifacts so evaluations can be reproduced and compared over time.
Reproducibility should also extend to the build itself. Reproducible Builds aims at independently verifiable deterministic builds. SLSA provenance provides verifiable metadata describing where, when, and how artifacts were built, and in-toto provides an attestation framework for expressing and verifying supply-chain claims. For a coding-AI evaluator, every release artifact should carry: source revision, toolchain digest, dataset snapshot, baseline model ID, prompt hash, registry version, random seeds, benchmark manifest, and test artifacts.
Audit logs should be first-class artifacts, not ad hoc text dumps. OpenTelemetry semantic conventions and MLflow tracing make it possible to store structured request IDs, span relationships, input/output metadata, and evaluation run identifiers consistently. For IOTA-like systems, audit records should also preserve result mode, normalization form, locale, ranking lanes, source atlas families, unknown rate, and provenance. That gives both humans and coding agents a stable forensic record.
Security and privacy need their own test discipline because code-evaluation harnesses often execute untrusted code. OpenAI’s HumanEval repository explicitly warns that model-generated code should not be run outside a robust security sandbox. NIST’s SSDF now includes a generative-AI profile, NIST’s AI RMF includes a generative-AI profile, and OWASP warns that crafted inputs, unvalidated outputs, and insecure downstream execution paths can turn LLM behavior into real system compromise. In practice, that means isolated execution, no ambient secrets, strict network and filesystem controls, time and memory caps, dependency scanning, and mandatory output validation before any generated code or converter output is trusted downstream.
Unicode is a security topic as much as an internationalization topic. UAX #15 explains why normalization creates unique binary representations for equivalent text, and Microsoft’s Unicode guidance warns that normalization can change the form of a string and that security checks should typically be applied to the normalized representation. For IOTA, that implies a concrete rule: normalize first, then validate against public-symbol and safety policies, and keep tests that compare pre- and post-normalization handling for all sensitive code paths.
The governance model that fits this best is simple: version the contract; freeze the corpus; pin the baseline; emit structured evidence; quarantine flakiness; regenerate labels through explicit pipelines; record every benchmark run with provenance; and never let approximate semantic success obscure missing evidence, missing safety checks, or weak executability. That is the shortest path to a coding AI that can actually tell when it is working—and when it is only producing something that looks convincing.