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.
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
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.
uv tool install mintmark # or: pip install mintmark
mintmark mint --pack 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. |
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
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.
Published on PyPI as mintmark, and
released on GitHub with the wheel, the source distribution, and a software bill
of materials attached. Publication runs through trusted publishing over OIDC
behind an approval gate, so no long-lived token exists in this repository.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mintmark-0.1.2.tar.gz.
File metadata
- Download URL: mintmark-0.1.2.tar.gz
- Upload date:
- Size: 395.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30cb44a86a27024511acd5653e1b46d894a4ece94d16b6541085f9fd4a296a30
|
|
| MD5 |
9c3245bb7d0e3b52177a5bfe2ef4ed62
|
|
| BLAKE2b-256 |
d83b92e85f13b9e950d8e0439217f463ef7c974cdc02d683879a90532e26d5cd
|
Provenance
The following attestation bundles were made for mintmark-0.1.2.tar.gz:
Publisher:
release.yml on lokomotifai/mintmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mintmark-0.1.2.tar.gz -
Subject digest:
30cb44a86a27024511acd5653e1b46d894a4ece94d16b6541085f9fd4a296a30 - Sigstore transparency entry: 2567931225
- Sigstore integration time:
-
Permalink:
lokomotifai/mintmark@d6976066131dc723f5a8c9fc6c10d0fa9a973bfa -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/lokomotifai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d6976066131dc723f5a8c9fc6c10d0fa9a973bfa -
Trigger Event:
push
-
Statement type:
File details
Details for the file mintmark-0.1.2-py3-none-any.whl.
File metadata
- Download URL: mintmark-0.1.2-py3-none-any.whl
- Upload date:
- Size: 113.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab4bcef08bdec9e0046625f219e9a2e124ba01b3645fbbfd0771c143a3e7f35d
|
|
| MD5 |
ab66a404065d1be0cd95d57e06086914
|
|
| BLAKE2b-256 |
0893c3d992982824cd90def90296ec36d5caff913c7f4f585f1ffcca126b332b
|
Provenance
The following attestation bundles were made for mintmark-0.1.2-py3-none-any.whl:
Publisher:
release.yml on lokomotifai/mintmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mintmark-0.1.2-py3-none-any.whl -
Subject digest:
ab4bcef08bdec9e0046625f219e9a2e124ba01b3645fbbfd0771c143a3e7f35d - Sigstore transparency entry: 2567931262
- Sigstore integration time:
-
Permalink:
lokomotifai/mintmark@d6976066131dc723f5a8c9fc6c10d0fa9a973bfa -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/lokomotifai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d6976066131dc723f5a8c9fc6c10d0fa9a973bfa -
Trigger Event:
push
-
Statement type: