Skip to main content

Mintmark

Mintmark

Turkish-first synthetic datasets that carry the mark of where they were struck.

Declare what to mint, hand it a seed, and get labeled data back with a manifest
that lets anyone else re-derive the same bytes and check them against you.

CI 698 tests 18 invariants, each with a named test Release v0.1.0 Not published to any registry Apache-2.0 license

Python 3.12 Two runtime dependencies No model in the generation path No network at mint time 18 labels in a closed taxonomy Türkçe

Start in two minutes · Read the claim · See what was verified · Türkçe


No model is anywhere in the generation path. Not to write a sentence, not to pick a name, not to smooth a distribution. Every value comes from a seeded stream, a curated lexicon, or a declared grammar, so the provenance of every character is traceable to a file you can read.

Turkish enterprises cannot move production data into test, evaluation, or AI pilot environments without KVKK exposure, and have had nothing realistic to use instead. Mintmark mints that data: fully synthetic, Turkish-first, deterministic, span-labeled, and sealed by a provenance manifest.

The name is numismatic. A mint mark is the small letter a mint strikes into a coin to say where it was made. A Mintmark dataset carries the same thing in its manifest, so a dataset that turns up six months later can still say what produced it.

Version 0.1, pre-release. Nothing is published to any package registry, and nothing here claims otherwise. The name is provisional pending trademark screening. What is true today: 698 tests pass, all eighteen invariants have named tests, and the byte-level determinism claim is observed on three platforms in a single CI run rather than asserted from one.

[!IMPORTANT] What Mintmark is not. It is not anonymization or masking of real data; it ingests no real data and cannot make yours safe. It is not legal advice and not a compliance guarantee. Synthetic realism has limits: the data follows declared distributions and curated lexicons, not any real population, so conclusions drawn from it are conclusions about the declarations. Generated phone numbers can coincide with assigned ones, because the Turkish numbering plan reserves no fictional range. This data is for testing systems. It is never for contacting anyone.

The unit of value in one picture

Diagram of the Mintmark pipeline: declared inputs enter a deterministic mint with no model, no network, no floating point and no transcendental call; the output is data, label sidecars, a manifest and checksums; verify and reproduce close the loop back to the same inputs

View the accessible SVG source

Most synthetic data tools make plausible records easy. Mintmark is concerned with what happens around that:

Question Mintmark's answer
Can this identifier belong to a real person? No. Safe mode emits provably checksum-invalid values, and verify runs the same validator a consumer would to prove it.
Will I get the same data next month? Yes, byte for byte, from the same engine version, pack digest, recipe, seed, policy, and format.
What produced this directory of files? MINTMARK.json, which binds the engine, the pack digest, the recipe, the seed, the policy, the taxonomy pin, and every checksum.
How do I know the labels line up? Every span is recorded as its surface is placed, and verify re-extracts every one from the text it indexes.
Can I check any of this without trusting you? Yes. mintmark reproduce re-mints from the manifest alone and compares bytes.
What did the data actually contain? The manifest records achieved distributions and label coverage next to the targets, whether or not they were met.

Start in two minutes

Offline after dependency bootstrap. No keys, no accounts, no network.

# Not on PyPI yet, so install from the repository.
uv tool install git+https://github.com/lokomotifai/mintmark
mintmark mint --pack packs/example --recipe demo --seed 42 --out ./demo-run
mintmark verify ./demo-run

demo-run/ will contain:

customer.jsonl                 100 records, one JSON object per line
transaction.jsonl              100 records, each with a rendered description
transaction.labels.jsonl       span offsets into each description
MINTMARK.json                  the provenance manifest
SHA256SUMS                     a checksum per emitted file

and mintmark verify prints exactly this:

manifest schema: valid
checksums: 3/3 match
identifier policy: safe (confirmed)
checksum-valid identifiers found: 0
taxonomy: hushmark-tr v0.1, pin af11b31e4916
label alignment: 100 documents, 81 spans
dataset license: CC-BY-4.0
attribution: mintmark-example 0.1.0 reference dataset (recipe demo, seed 42), lokomotifai, licensed CC-BY-4.0

A test asserts that block against what verify actually prints, so this example cannot go stale while looking current.

One record, as emitted:

{"customer_id":"CUST-00000000","first_name":"Kaan","last_name":"Kılıç","national_id":"71773625043","email":"kaan.kilic.1256@example.org","phone":"+90 525 886 73 05","il":"Batman","segment":"affluent","balance_kurus":277663,"currency":"TRY"}

Every field there is synthetic. The national identity number fails its own check digit rule. The address sits under a domain nobody can register. The balance is integer kuruş, because a float would put the emitted bytes at the mercy of the platform.

Identifiers cannot be real

Six engines, each with a safe default and an opt-in validator mode. Safe mode is not a promise; it is a property the verifier re-checks on the artifacts.

Engine What makes a safe value unable to be real
TCKN Both public check rules are computed correctly, then the second is corrupted by a nonzero offset. The number's visible shape is untouched and the invalidity sits exactly where a checker looks.
VKN The same, over an algorithm verified against two independent open implementations across 200 000 inputs before a line of it was written.
IBAN Check digits are shifted within the admissible 02 to 98 window, and the bank code is 99999, verified absent from the TCMB participant list. Even a validator-mode IBAN names no real institution.
PAN Sixteen digits beginning with 9, a major industry identifier no commercial card network uses. That holds under both policies. Default emission is masked.
PHONE Format-correct only. The Turkish numbering plan reserves no fictional mobile range, so coincidence is possible. This is documented rather than hidden, and the purpose limitation follows: test systems, never contact anyone.
EMAIL Only .example and the example.com family, reserved by RFC 2606 and RFC 6761 so that nobody can ever register them.

validator mode exists so you can test your own validation logic against something that passes. It is opt-in per mint, and every dataset minted under it carries a warning block that verify refuses to accept as missing.

The determinism claim, stated exactly

Identical engine version, pack digest, recipe, seed, identifier policy, and output format produce byte-identical data files and label sidecars, on CPython 3.12 on Linux x86_64, Linux arm64, and macOS arm64.

The manifest's provenance block, meaning the creation timestamp and the invocation line, is excluded. Everything else in the manifest is included. Windows is not claimed and is not tested.

Every term is load-bearing, and the claim is narrow because keeping it is someone's job. What makes it hold:

Constraint Why
No float in emitted data A float's text form depends on the platform's formatting of a binary approximation. Money is integer kuruş; rates are decimal strings.
No transcendental call in the mint path libm results differ across platforms and libm versions. Log-normal amounts come from 1024-knot inverse-CDF tables generated offline and interpolated with integer arithmetic.
A stream per generation site Adding a field shifts no other field's values. One shared stream would shift everything after the insertion point and silently invalidate every published manifest.
A NUL separator in stream derivation Without it, a pack named ab at version c hashes identically to a pack named a at version bc, aliasing two streams into one.
Rejection sampling, not modulo Modulo over-represents the first residues. A fixture whose purpose is fairness cannot carry a skew nobody declared.
Declaration order in serialization Not sorted, not insertion order. A serializer change must not report a mismatch that is not one.

tests/golden/demo-run/ holds committed bytes, not a re-execution. Minting twice in one process proves the code is a function of its inputs; only committed bytes prove today's code is the same function yesterday's was.

What Mintmark protects, and what it does not

It does It does not
Produce data that contains no real personal information, because it ingests none Anonymize or mask your real data. That is Hushmark's side of the boundary
Give you a record that lets a third party re-derive and check the dataset Certify that dataset for any purpose, or make any compliance claim
Label spans against a closed taxonomy so a detector can be scored Tell you whether your detector is good enough
State exactly which platforms the byte claim covers Cover platforms it has not been observed on
Keep every generated organization fictional and scanned against a real-institution list Guarantee a name is unclaimed in every jurisdiction and register
Emit checksum-invalid identifiers by default Prevent a phone number from coinciding with an assigned one; no fictional range exists to draw from

Mintmark is not legal advice and not a compliance guarantee. It describes what the software does. Mapping that to your obligations is your work.

One hub, thin spokes

Diagram of the Mintmark family: a single engine repository with three sector pack repositories hanging from it, banking, insurance and human resources, plus a fourth drawn dashed and marked deferred for health

View the accessible SVG source

This repository is the engine. Sector packs are separate repositories carrying declarations and data with no engine code at all: their only Python lives in tests and imports nothing beyond the public API.

Repository Status Contents
mintmark this repository generation, identifiers, annotation, manifests, the CLI, one example fixture pack
mintmark-banking first spoke customers, accounts, cards, transactions, complaints, KYC notes, support transcripts
mintmark-insurance second spoke policyholders, policies, claims, payments, claim notes, call transcripts
mintmark-hr third spoke employees, position history, leave, payroll, performance and recruiter notes, HR requests
health deferred Its special-category density needs a stricter governance review before a brief is even written

Each pack pins this engine by a version range with a closed upper bound, so a future engine cannot silently change what a published manifest reproduces.

Verified rather than assumed

Four facts this project depends on live in public registries and specifications rather than in any document here. Coding them from memory would have produced software that is confidently wrong, so each was checked against primary sources and the record kept.

Fact Source Outcome
The VKN check-digit algorithm Two independent open implementations, in different languages by different authors Zero disagreements across 200 000 random inputs; both reproduce the published test vector
IBAN bank code 99999 is unassigned TCMB payment systems participant list, revision 072025 71 participants, codes 0001 to 0807, nothing in the 9xxxx range
Turkey is permanently UTC+3 The IANA time zone database One offset across 2017 to 2030, daylight saving zero at every sampled instant
The institution denylist The same TCMB list 70 entries covering all 71 participants, each matched back against its source by a test

Full records with retrieval dates are in docs/normative-verification.md. The two that drift are re-checked weekly by a separate, network-labeled workflow that opens an issue and never updates anything on its own.

Repository map

src/mintmark/
  engine/         streams, SplitMix64, unbiased draws, fixed-point tables, templates
  identifiers/    tckn, vkn, iban, pan, phone, email; safe and validator modes
  annotate/       the closed taxonomy, span capture, rendering, sidecars
  packs/          strict fail-closed loading, schemas, the canonical pack digest
  emit/           canonical JSONL and CSV, atomic output
  manifest/       MINTMARK.json, checksums, verify
  lexicons/       Turkish base lexicons and the institution denylist
  mint.py         the composition root, where the layers meet
  cli.py          seven verbs, five exit codes, stable JSON payloads
schemas/          pack and manifest JSON Schemas, versioned
packs/example/    the fixture pack the quickstart uses
assets/           committed distribution tables and the denylist
tools/            the offline table generator, the prose lint, the canary check
tests/            unit, property, golden, adversarial, conformance

Module dependency direction is enforced by import-linter in required CI, and engine imports only the standard library. That is not tidiness: it is what makes the determinism claim checkable, because every value the engine produces comes from arithmetic this repository specifies rather than from a dependency's release schedule.

Develop the repository

uv sync
uv run ruff format --check . && uv run ruff check .
uv run mypy --strict src/
uv run lint-imports
uv run pytest
uv run python tools/mdlint.py .

All of it runs offline once dependencies are installed. Two checks are worth knowing about before you meet them.

tools/mdlint.py enforces the language rules on prose in both languages: sentence-case headings, a banned promotional vocabulary, and no em dash or en dash anywhere. Quoted third-party text is exempted with a marker that has to carry a reason.

tools/canary.py proves that private planning material is absent from the tree and from built artifacts. The canary string is never committed, because committing it would plant the very thing the check looks for; it arrives through MINTMARK_CANARY and only its digest lives here.

Project status

Version 0.1, pre-release. The public surface under semantic versioning is the command-line grammar, the exit codes, the --json payloads, the library's two functions, both JSON Schemas, and the bytes a fixed seed produces.

That last one deserves emphasis. A change that alters emitted bytes for a fixed seed is a major version event even when no signature moved, because it breaks the reproducibility of every published manifest.

Version 0.1.0 is tagged and released on GitHub with the wheel, the source distribution, and a software bill of materials attached. Nothing is published to PyPI, so install from this repository rather than by package name; the name on that index is unclaimed and a command naming it there installs something this project did not build.

The name Mintmark is provisional pending trademark screening at TURKPATENT, EUIPO, USPTO, and WIPO. This README will say so until that changes.

Community contract

Contributions are accepted under the Developer Certificate of Origin 1.1 with no contributor license agreement. See CONTRIBUTING.md for the checks to run and the language rules to follow, GOVERNANCE.md for how decisions are made and what the single-maintainer rule currently is, and SECURITY.md for the private reporting route and what counts as a vulnerability here.

README.md is canonical and README.tr.md is a full mirror, not a summary. A change to one without the other fails review, and a test compares their structure.

Documentation

Document What it covers
docs/determinism.md The claim, why each term is narrow, and how to reproduce a published dataset
docs/taxonomy.md The eighteen labels, the pin, and what happens when upstream moves
docs/normative-verification.md What was verified, against which source, on what date, with what outcome
docs/engineering-notes.md Build quirks, environment traps, and the invariant-to-test map

Why this exists

The hushmark-tr model card asks adopters to evaluate the detector on representative data before production use. That is an honest limitation, and it had no honest answer in Turkish: the representative data did not exist, and production data could not be used to make it.

Mintmark is that answer. One sibling's stated limitation is the other sibling's product definition.

License and trademark

Code is Apache-2.0. See LICENSE and NOTICE.

Datasets minted by this engine carry the terms their pack declares, written into MINTMARK.json and printed by verify. Every pack in this family declares CC BY 4.0: any use including commercial, with credit. See LICENSE-DATASETS.md.

What a synthetic dataset does and does not mean under Turkish data protection law is set out in docs/kvkk.md.

The license grants no right to the Mintmark name or logo. See TRADEMARKS.md for what fair community use covers.

Part of the lokomotifai family: Pactmark seals agent execution · Hushmark seals data egress · Permitmark seals secret ingress · Mintmark seals data supply

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mintmark-0.1.1.tar.gz (393.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mintmark-0.1.1-py3-none-any.whl (113.0 kB view details)

Uploaded Python 3

File details

Details for the file mintmark-0.1.1.tar.gz.

File metadata

  • Download URL: mintmark-0.1.1.tar.gz
  • Upload date:
  • Size: 393.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mintmark-0.1.1.tar.gz
Algorithm Hash digest
SHA256 fd05cb1c1fee466b4e827d385859d4fa6998a3ff16bb28c80aeb2057fab6a465
MD5 802dd705c019530920ec044c51f98c86
BLAKE2b-256 5723804fc85ed817c7fd8b8dbc4acf0b7f0b702e538401d1f7c8427299e8c564

See more details on using hashes here.

Provenance

The following attestation bundles were made for mintmark-0.1.1.tar.gz:

Publisher: release.yml on lokomotifai/mintmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mintmark-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: mintmark-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 113.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for mintmark-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7cc3f6ebb7662e812eb53008faf064e22e38fac8bd63336fe202b06c716b2430
MD5 2e699fc3bac1b8a584a948bc2fe541a9
BLAKE2b-256 4dbe59e2d692cfcc20380f2691eec584e2dcced1450faae43d02e76cc7303a13

See more details on using hashes here.

Provenance

The following attestation bundles were made for mintmark-0.1.1-py3-none-any.whl:

Publisher: release.yml on lokomotifai/mintmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page