mintmark 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. mintmark-0.2.0/CHANGELOG.md +321 -0
  2. {mintmark-0.1.2 → mintmark-0.2.0}/NOTICE +2 -2
  3. {mintmark-0.1.2 → mintmark-0.2.0}/PKG-INFO +13 -12
  4. {mintmark-0.1.2 → mintmark-0.2.0}/README.md +11 -10
  5. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/pack.yaml +1 -1
  6. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/recipes/demo.yaml +0 -2
  7. {mintmark-0.1.2 → mintmark-0.2.0}/pyproject.toml +6 -2
  8. {mintmark-0.1.2 → mintmark-0.2.0}/schemas/manifest.schema.json +66 -24
  9. {mintmark-0.1.2 → mintmark-0.2.0}/schemas/pack.schema.json +26 -13
  10. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/__init__.py +3 -1
  11. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/annotate/render.py +19 -0
  12. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/api.py +4 -2
  13. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/cli.py +205 -57
  14. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/emit/writer.py +46 -14
  15. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/draws.py +2 -0
  16. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/templates.py +69 -5
  17. mintmark-0.2.0/src/mintmark/engine/version.py +5 -0
  18. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/special_descriptors.yaml +74 -15
  19. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/manifest/document.py +30 -11
  20. mintmark-0.2.0/src/mintmark/manifest/io.py +230 -0
  21. mintmark-0.2.0/src/mintmark/manifest/safety.py +37 -0
  22. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/manifest/sums.py +11 -8
  23. mintmark-0.2.0/src/mintmark/manifest/verify.py +778 -0
  24. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/mint.py +173 -31
  25. mintmark-0.2.0/src/mintmark/packs/digest.py +160 -0
  26. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/packs/loader.py +72 -4
  27. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/packs/model.py +397 -50
  28. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/alias/pack.yaml +1 -1
  29. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/anchor/pack.yaml +1 -1
  30. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/bad-name-pattern/pack.yaml +1 -1
  31. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/duplicate-key/pack.yaml +1 -1
  32. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/float-weight/pack.yaml +1 -1
  33. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/merge-key/pack.yaml +1 -1
  34. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/missing-schema-version/pack.yaml +1 -1
  35. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/multiple-documents/pack.yaml +1 -1
  36. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/open-ended-requires-core/pack.yaml +1 -1
  37. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/unknown-field/pack.yaml +1 -1
  38. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/valid/pack.yaml +1 -1
  39. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/wrong-locale/pack.yaml +1 -1
  40. mintmark-0.2.0/tests/adversarial/test_numeric_resource_limits.py +147 -0
  41. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/test_pack_rejection.py +59 -1
  42. mintmark-0.2.0/tests/adversarial/test_tamper_detection.py +497 -0
  43. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/test_template_grammar.py +111 -0
  44. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/pack.yaml +1 -1
  45. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/recipes/full.yaml +0 -5
  46. {mintmark-0.1.2 → mintmark-0.2.0}/tests/golden/demo-run/DIGESTS.json +6 -2
  47. {mintmark-0.1.2 → mintmark-0.2.0}/tests/golden/demo-run/transaction.jsonl +84 -84
  48. mintmark-0.2.0/tests/golden/demo-run/transaction.labels.jsonl +100 -0
  49. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_draws.py +18 -0
  50. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_cli.py +34 -0
  51. mintmark-0.2.0/tests/unit/test_declared_controls.py +309 -0
  52. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_emit.py +39 -0
  53. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_mint_invariants.py +82 -5
  54. mintmark-0.2.0/tests/unit/test_pack_digest.py +233 -0
  55. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_readme_mirror.py +40 -0
  56. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_workflows.py +59 -0
  57. mintmark-0.1.2/CHANGELOG.md +0 -159
  58. mintmark-0.1.2/src/mintmark/manifest/verify.py +0 -362
  59. mintmark-0.1.2/src/mintmark/packs/digest.py +0 -58
  60. mintmark-0.1.2/tests/adversarial/test_tamper_detection.py +0 -256
  61. mintmark-0.1.2/tests/golden/demo-run/transaction.labels.jsonl +0 -100
  62. mintmark-0.1.2/tests/unit/test_pack_digest.py +0 -112
  63. {mintmark-0.1.2 → mintmark-0.2.0}/.gitignore +0 -0
  64. {mintmark-0.1.2 → mintmark-0.2.0}/LICENSE +0 -0
  65. {mintmark-0.1.2 → mintmark-0.2.0}/assets/brand/mintmark-logo.png +0 -0
  66. {mintmark-0.1.2 → mintmark-0.2.0}/assets/brand/mintmark-logo.svg +0 -0
  67. {mintmark-0.1.2 → mintmark-0.2.0}/assets/denylist/institutions-tr.txt +0 -0
  68. {mintmark-0.1.2 → mintmark-0.2.0}/assets/readme/family-topology.png +0 -0
  69. {mintmark-0.1.2 → mintmark-0.2.0}/assets/readme/family-topology.svg +0 -0
  70. {mintmark-0.1.2 → mintmark-0.2.0}/assets/readme/mint-pipeline.png +0 -0
  71. {mintmark-0.1.2 → mintmark-0.2.0}/assets/readme/mint-pipeline.svg +0 -0
  72. {mintmark-0.1.2 → mintmark-0.2.0}/assets/tables/CHECKSUMS +0 -0
  73. {mintmark-0.1.2 → mintmark-0.2.0}/assets/tables/balances.json +0 -0
  74. {mintmark-0.1.2 → mintmark-0.2.0}/assets/tables/txn_amounts.json +0 -0
  75. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/README.md +0 -0
  76. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/fields/customer.yaml +0 -0
  77. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/fields/transaction.yaml +0 -0
  78. {mintmark-0.1.2 → mintmark-0.2.0}/packs/example/templates/txn_descriptions/set.yaml +0 -0
  79. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/annotate/__init__.py +0 -0
  80. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/annotate/sidecar.py +0 -0
  81. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/annotate/spans.py +0 -0
  82. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/annotate/taxonomy.py +0 -0
  83. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/emit/__init__.py +0 -0
  84. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/emit/canonical.py +0 -0
  85. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/emit/csv_writer.py +0 -0
  86. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/__init__.py +0 -0
  87. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/fold.py +0 -0
  88. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/prng.py +0 -0
  89. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/records.py +0 -0
  90. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/streams.py +0 -0
  91. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/engine/tables.py +0 -0
  92. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/__init__.py +0 -0
  93. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/email.py +0 -0
  94. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/iban.py +0 -0
  95. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/pan.py +0 -0
  96. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/phone.py +0 -0
  97. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/policy.py +0 -0
  98. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/tckn.py +0 -0
  99. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/identifiers/vkn.py +0 -0
  100. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/__init__.py +0 -0
  101. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/given_names_tr.yaml +0 -0
  102. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/occupations_tr.yaml +0 -0
  103. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/provinces_tr.yaml +0 -0
  104. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/street_parts_tr.yaml +0 -0
  105. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/data/surnames_tr.yaml +0 -0
  106. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/lexicons/denylist.py +0 -0
  107. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/manifest/__init__.py +0 -0
  108. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/packs/__init__.py +0 -0
  109. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/packs/semver.py +0 -0
  110. {mintmark-0.1.2 → mintmark-0.2.0}/src/mintmark/py.typed +0 -0
  111. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/empty-file/pack.yaml +0 -0
  112. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/non-mapping-root/pack.yaml +0 -0
  113. {mintmark-0.1.2 → mintmark-0.2.0}/tests/adversarial/packs/tab-indentation/pack.yaml +0 -0
  114. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/account.yaml +0 -0
  115. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/card.yaml +0 -0
  116. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/complaint_ticket.yaml +0 -0
  117. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/customer.yaml +0 -0
  118. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/kyc_note.yaml +0 -0
  119. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/support_transcript.yaml +0 -0
  120. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/fields/transaction.yaml +0 -0
  121. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/lexicons/ratings.yaml +0 -0
  122. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/templates/complaints/set.yaml +0 -0
  123. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/templates/kyc_notes/set.yaml +0 -0
  124. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/pack/templates/transcripts/set.yaml +0 -0
  125. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conformance/test_contract_coverage.py +0 -0
  126. {mintmark-0.1.2 → mintmark-0.2.0}/tests/conftest.py +0 -0
  127. {mintmark-0.1.2 → mintmark-0.2.0}/tests/golden/demo-run/customer.jsonl +0 -0
  128. {mintmark-0.1.2 → mintmark-0.2.0}/tests/golden/prng_vectors.json +0 -0
  129. {mintmark-0.1.2 → mintmark-0.2.0}/tests/golden/test_golden_bytes.py +0 -0
  130. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_fold_and_email.py +0 -0
  131. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_records.py +0 -0
  132. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_render.py +0 -0
  133. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_safe_mode_purity.py +0 -0
  134. {mintmark-0.1.2 → mintmark-0.2.0}/tests/property/test_span_alignment.py +0 -0
  135. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_canary.py +0 -0
  136. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_community_mirrors.py +0 -0
  137. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_denylist.py +0 -0
  138. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_module_boundaries.py +0 -0
  139. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_no_libm.py +0 -0
  140. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_packaging.py +0 -0
  141. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_prng.py +0 -0
  142. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_prose_lint.py +0 -0
  143. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_repository_inventory.py +0 -0
  144. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_streams.py +0 -0
  145. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_tables.py +0 -0
  146. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_taxonomy.py +0 -0
  147. {mintmark-0.1.2 → mintmark-0.2.0}/tests/unit/test_toolchain.py +0 -0
  148. {mintmark-0.1.2 → mintmark-0.2.0}/tools/canary.py +0 -0
  149. {mintmark-0.1.2 → mintmark-0.2.0}/tools/gen_tables.py +0 -0
  150. {mintmark-0.1.2 → mintmark-0.2.0}/tools/mdlint.py +0 -0
@@ -0,0 +1,321 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [keep a changelog](https://keepachangelog.com/en/1.1.0/), and this project uses
5
+ [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ The public surface under semantic versioning is: the command-line grammar, the
8
+ exit codes, every `--json` payload, the library's exported functions and their
9
+ returned dataclasses, the pack schema, the manifest schema, and the byte-level
10
+ output for a fixed set of inputs. A change that alters emitted bytes for a fixed
11
+ seed is a major version event even when no signature changed, because it breaks
12
+ the reproducibility of every published manifest.
13
+
14
+ ## 0.2.0 - 2026-08-23
15
+
16
+ A security and conformance review of the three sector packs found one defect
17
+ repeated in seven places: a field parsed, validated against the schema, asserted
18
+ by a test, and then read by nothing. Every item below closes one of those. Two of
19
+ them move emitted bytes for a fixed seed, which this project calls a major
20
+ version event, so the version moves rather than the golden files quietly.
21
+
22
+ ### Hardened against a hostile pack and a hostile dataset
23
+
24
+ Fourteen commits landed before this release was cut and are recorded here rather
25
+ than left to the git log, because each one changes what the engine refuses.
26
+
27
+ - **Resource budgets on everything a pack declares.** Strict YAML parsing, pack
28
+ declarations, document templates, and numeric work factors all carry explicit
29
+ bounds now, so a pack cannot make the loader do unbounded work. Templates are
30
+ compiled once before any record is generated, and a nesting depth limit refuses
31
+ a template that recurses past what the parser supports.
32
+ - **Sampler bounds are checked rather than assumed.** An unsupported bound is
33
+ refused instead of producing a draw nobody can reason about.
34
+ - **Atomic staging writes are isolated**, and the pack digest streams its inputs
35
+ from a confined set of paths rather than reading whatever it is pointed at.
36
+ - **Untrusted dataset file access is hardened.** `verify` reads a dataset through
37
+ a reader that bounds what it will open, and the whole verification body sits
38
+ behind a boundary that turns a hostile input into a report rather than a
39
+ traceback.
40
+ - **Every claim in a manifest is re-derived rather than trusted.** Record counts,
41
+ distributions, entity coverage, the achieved counts and `met` flags on coverage
42
+ targets, and the fixed-contract text are all recomputed from the data and
43
+ compared.
44
+ - **Safe output and annotation invariants are enforced at mint time**, including
45
+ the label a field may carry for its generator, so a pack cannot declare a
46
+ document field or an identifier field with a label that contradicts it.
47
+ - **Pack compatibility is enforced deterministically.** `requires_core` is checked
48
+ against the running core on every load rather than only when a caller asks.
49
+ - **CI and release trust boundaries are sealed**, and the pack layer keeps its
50
+ dependency boundaries.
51
+
52
+ ### Fixed, and it changes what a verifier reports
53
+
54
+ - **`verify` reported zero checksum-valid identifiers in datasets where every
55
+ identifier was checksum-valid.** The sweep ran only under the safe policy while
56
+ the counter it fills was printed under both, in the rendered report and in the
57
+ `--json` payload. A validator-policy dataset therefore reported
58
+ `checksum_valid_identifiers: 0`, and a script gating on that number let through
59
+ exactly the datasets it was written to stop. The sweep now runs under both
60
+ policies. Under safe a hit is still a problem, because safe mode is the
61
+ product's safety claim; under validator the count is the expected outcome and
62
+ is recorded as a fact.
63
+
64
+ - **A declared coverage target was recorded and never checked.** Every manifest
65
+ carried the target, the achieved count, and a `met` flag, and nothing read any
66
+ of them, so an evaluation set could ship without a whole label and still verify
67
+ clean. `verify` now fails on a missed target. A mint that overrode its record
68
+ counts is exempt: `packcheck` mini-mints twenty-five records against targets in
69
+ the hundreds, and a deliberately shrunken run is not a claim the recipe made.
70
+
71
+ - **The validator warning claimed more than the engines deliver.** It said the
72
+ values belong to no real person, account, or institution. That holds for an
73
+ IBAN, a PAN, and an email address, each of which sits in a range nobody can
74
+ hold. A TCKN and a VKN have no such reserved range, so a checksum-valid one is
75
+ indistinguishable from an issued number. The fixed text now says which is
76
+ which.
77
+
78
+ ### Fixed, and it moves emitted bytes
79
+
80
+ - **Template weights were ignored.** Every template entry carries a required
81
+ `weight`, the schema validates it as a decimal string, and the renderer picked
82
+ uniformly regardless. A set declared at 0.35, 0.25, 0.25, 0.15 emitted an even
83
+ quarter each. Selection now uses the same weighted draw the enum generators
84
+ use.
85
+
86
+ - **A pack could not contribute entity surfaces.** `{entity:ORG}` drew from the
87
+ core's curated list and nothing else, so every pack in the family shared one
88
+ twelve-name organization vocabulary, and an evaluation set built on it could be
89
+ passed by memorizing them. `pack.yaml` gains an optional `entity_lexicons` map
90
+ from label to the pack's own lexicons. The core list stays the floor: pack
91
+ surfaces are appended, never substituted.
92
+
93
+ - **PERSON surfaces were a list of twelve full names.** The descriptor note
94
+ already said they came from the same common Turkish name pool the structured
95
+ fields draw from, so they are now composed from it: 60 given names against 50
96
+ surnames, 3000 surfaces, in a fixed order so the draw stays a plain index. A
97
+ label entry in the descriptor file may declare `compose` instead of `values`.
98
+
99
+ ### Added
100
+
101
+ - **`{lex:name}` in the template grammar.** A draw from a named lexicon, emitted
102
+ without a label, so a template can vary its ordinary words instead of repeating
103
+ one carrier sentence. Domain vocabulary is not personal data and carries no
104
+ span.
105
+
106
+ - **Two reachability rules on pack loading.** A lexicon nothing draws from, and a
107
+ template set no field renders, are refused by name. Three sector packs shipped
108
+ eight lexicons between them that reached no generator at all: source-noted,
109
+ denylist-tested, guarded by their own tests, and absent from every byte those
110
+ packs emit.
111
+
112
+ ### Changed
113
+
114
+ - **A recipe that names an identifier policy now decides it.** The field was
115
+ parsed into the `Recipe` dataclass and read nowhere, so a recipe pinned to
116
+ `safe` minted checksum-valid identifiers the moment a caller passed
117
+ `--identifier-policy validator`. Naming a different policy than the recipe
118
+ names is refused. Naming the same one is allowed, because `reproduce` replays
119
+ what a manifest recorded and cannot know which of the two decided it.
120
+ `--identifier-policy` now defaults to unset rather than to `safe`.
121
+
122
+ ### Removed
123
+
124
+ - **`doc_mix` and `emit_child_outside_window` from the recipe schema.**
125
+ `doc_mix` restated what the record counts already fix, and nothing read it;
126
+ `emit_child_outside_window` carried a schema description of behaviour no code
127
+ implemented. The template-set existence check `doc_mix` provided is replaced by
128
+ the stronger reachability rule above.
129
+
130
+ ## 0.1.3 - 2026-08-22
131
+
132
+ ### Fixed, and it changes every manifest
133
+
134
+ - **The pack digest covered files that cannot affect what a pack emits.** It
135
+ enumerated the whole pack directory minus a short denylist, which meant it
136
+ covered README files, the changelog, the test suite, the lockfile, the vendored
137
+ engine wheel, compiled `__pycache__` output, and `PLAN.md`, a file the sector
138
+ packs deliberately keep out of git.
139
+
140
+ Three consequences, all observed rather than reasoned about. A clean clone and
141
+ a working checkout of the same commit produced different digests. Running the
142
+ suite under a different pytest version changed the digest through the `.pyc`
143
+ files. Editing documentation changed the digest of a pack whose declarations
144
+ had not moved. One pack produced three different digests for one set of
145
+ declarations: `9548e8fd` in a working tree, `144b703a` from a clean clone, and
146
+ `a9552d15` in an already published dataset.
147
+
148
+ A digest behaving that way cannot do the job it exists for, which is to let
149
+ somebody holding a dataset tell whether a pack they have is the pack it came
150
+ from. It now covers `pack.yaml` and the `fields/`, `recipes/`, `templates/`,
151
+ `lexicons/`, and `assets/` directories, by allowlist rather than denylist,
152
+ because every failure above was something nobody thought to deny.
153
+
154
+ Every manifest this engine writes now records a different `pack.digest` for the
155
+ same declarations. No emitted data moves: the digest seeds nothing.
156
+
157
+ - **`reproduce` could not find the pack the engine itself ships**, so the
158
+ quickstart's own output could not be reproduced by the command the README
159
+ advertises as the check that makes a manifest mean something.
160
+
161
+ - **`reproduce` reported `differs outside the excluded provenance block`**, which
162
+ was true and useless. It now names each field that differs with both values. A
163
+ difference confined to the engine version is reported as what it is rather than
164
+ as a mismatch, because the determinism claim covers a fixed engine version and
165
+ a newer engine reproducing every byte is a stronger result than the claim, not
166
+ a failure of it.
167
+
168
+ ### Notes
169
+
170
+ Found by auditing the published product rather than the source tree: cloning the
171
+ packs, installing the engine from PyPI, and running the documented commands
172
+ against the released datasets.
173
+
174
+ ## 0.1.2 - 2026-08-22
175
+
176
+ ### Fixed
177
+
178
+ - The example pack shipped in the wheel and could not be reached. It is there so
179
+ the quickstart works without cloning anything, which is the whole reason it is
180
+ shipped, but `--pack packs/example` is a path that exists only in a checkout.
181
+ Anyone who installed 0.1.1 from PyPI and followed the README walked into
182
+ `pack: not-a-directory`. Found by installing the published package and running
183
+ the README's own first command against it.
184
+
185
+ `--pack example` now resolves to the packaged pack. A local path always wins,
186
+ so this cannot shadow a real directory, and an unrecognized name is returned
187
+ untouched so the loader still fails with the path the user typed rather than
188
+ rescuing a typo into some other pack.
189
+
190
+ ### Changed
191
+
192
+ - Both READMEs install by package name again and the quickstart uses
193
+ `--pack example`. The claim that nothing was published was true until 0.1.1
194
+ and is not any more.
195
+
196
+ ## 0.1.1 - 2026-08-22
197
+
198
+ ### Added
199
+
200
+ - Publication to PyPI, over trusted publishing. The release workflow was written
201
+ and left disabled so its mechanics could be reviewed before they ever ran; this
202
+ enables it. No long-lived token is stored in this repository and none is passed
203
+ to a step, because PyPI verifies the workflow identity directly.
204
+
205
+ Three gates stand between a tag and a published release, and none of them is a
206
+ reviewer's attention. The tag must agree with the version in `pyproject.toml`
207
+ and with the version the package reports. The full gate runs first and
208
+ publication depends on it. The `pypi` environment requires the owner's approval
209
+ and admits only `v*` tags, so a push to main cannot reach it.
210
+
211
+ ### Notes
212
+
213
+ The package is unchanged from 0.1.0. This version exists because publication is a
214
+ repository change that needs a tag to carry it, and moving the 0.1.0 tag would
215
+ have broken the immutability that repository's own tag ruleset enforces.
216
+
217
+ A version already on PyPI cannot be replaced, and deleting a release does not
218
+ free its number. The workflow refuses on a version mismatch rather than resolving
219
+ one.
220
+
221
+ ## 0.1.0 - 2026-08-22
222
+
223
+ ### Changed, and it moved emitted bytes
224
+
225
+ - The manifest gained a `license` block and its schema version went to 2. A
226
+ dataset leaves this project as a directory of files, and before this there was
227
+ nothing in that directory saying under what terms it could be used. An
228
+ attribution requirement a consumer cannot find in the artifact is not a
229
+ requirement. The block carries the code license, the dataset license the pack
230
+ declared, and a ready credit line; `verify` prints all three, and stripping the
231
+ block fails verification like any other tampering.
232
+ - `pack.yaml` requires `dataset_license`, from a closed set. The engine writes
233
+ this into every manifest it produces, and a free-text field would put a typo,
234
+ or terms nobody vetted, onto a published artifact. Declaring it changes the
235
+ pack digest, which changes emitted bytes for a fixed seed, which is why every
236
+ pack in the family took a version bump alongside it.
237
+
238
+ - The special-category descriptor lexicons moved into a curated YAML file and
239
+ grew to 90 entries. Expanding a lexicon changes the draw for every subsequent
240
+ index, so emitted bytes moved for a fixed seed. **Under this project's own rule
241
+ that is a major version event.** It is harmless only because nothing has been
242
+ published: there is no manifest this breaks. The reason is recorded in
243
+ `tests/golden/demo-run/DIGESTS.json` beside the regenerated goldens.
244
+ - `special_rate` now governs what it claimed to govern. A recipe declared it and
245
+ nothing read it, so template authors fixed the density with literal
246
+ probabilities and the recipe field was decoration. Templates now write
247
+ `[?special: ...]` and the rate comes from the recipe.
248
+
249
+ ### Added
250
+
251
+ - Turkish mirrors of every community document: contributing, conduct,
252
+ governance, security, and support, each linked from its original and held in
253
+ step by a test. The audience for this project reads Turkish, and a README
254
+ mirror alone left a contributor reading the project's own rules in a second
255
+ language. The conduct mirror records that it is our own rendering rather than
256
+ the official one, because the Contributor Covenant publishes Turkish at 2.0
257
+ while this repository adapts 2.1.
258
+ - `docs/kvkk.md` and its Turkish mirror: what this project produces and what it
259
+ does not claim under law 6698, with a table mapping the taxonomy's
260
+ special-category labels to the categories the law enumerates, and naming the
261
+ three that no label covers.
262
+ - `LICENSE-DATASETS.md`, `CITATION.cff`, issue and pull request templates,
263
+ `CODEOWNERS`, and grouped monthly dependency updates.
264
+
265
+ - The `derived:flag_unless` rule, which turns a sentinel enum value into a
266
+ boolean so a row can carry both which anomaly it is and whether it is one,
267
+ without two independent draws that can disagree.
268
+ - An optional `age_years: [low, high]` parameter on `datetime_window`, which
269
+ draws from the span that would give a person that age at the start of the
270
+ recipe window. Without it a birth date is drawn from the recipe window, so
271
+ every person in a dataset describing one year was also born in that year. The
272
+ field is a valid date, the label is right, the span aligns and the manifest
273
+ verifies, so nothing in the suite caught it; it is only wrong to a reader. The
274
+ parameter is optional and a field that omits it behaves exactly as before, so
275
+ no existing declaration had to move. Declaring it on a field whose generator
276
+ cannot read it is rejected by name at pack load, because a parameter nothing
277
+ reads is worse than one that fails loudly.
278
+
279
+ - Deterministic generation engine: SplitMix64 over 64-bit modular arithmetic,
280
+ per-site stream derivation, unbiased bounded and weighted draws, and
281
+ continuous distributions sampled from committed fixed-point inverse-CDF tables
282
+ so that no transcendental function runs in the mint path.
283
+ - Six identifier engines, each with a `safe` default that emits provably
284
+ checksum-invalid values and an opt-in `validator` mode that is watermarked in
285
+ the manifest.
286
+ - A closed eighteen-label taxonomy pinned by digest, span recording that
287
+ survives whitespace normalization, and a label sidecar format that binds spans
288
+ to the exact text they index.
289
+ - Strict, fail-closed pack loading: duplicate keys, anchors, aliases, merge
290
+ keys, multi-document files, non-mapping roots, tab indentation, and unknown
291
+ fields are each rejected by name.
292
+ - Canonical JSONL and CSV emission with no float in emitted data, and atomic
293
+ output so an interrupted mint leaves no directory that looks like a dataset.
294
+ - A provenance manifest with checksums, `verify` that recomputes every claim it
295
+ makes, and `reproduce` that re-mints from the manifest and compares bytes.
296
+ - A command-line surface of seven verbs with a five-value exit-code contract and
297
+ stable `--json` payloads, plus a two-function library API.
298
+ - An example fixture pack, shipped in both the wheel and the sdist, used by the
299
+ quickstart and the test suite.
300
+ - A real-institution denylist built from a verified public registry, scanned in
301
+ required CI over lexicons, templates, and golden outputs.
302
+ - English and Turkish READMEs, kept in step by a test that compares their
303
+ structure and checks the quickstart's promised output against what `verify`
304
+ actually prints.
305
+
306
+ ### Verified rather than assumed
307
+
308
+ The VKN check-digit algorithm, against two independent open implementations
309
+ cross-checked over 200 000 inputs. The unassigned status of IBAN bank code
310
+ 99999, against the TCMB participant list. Turkey's permanent UTC+3 status,
311
+ against the IANA time zone database. The institution denylist, against the same
312
+ TCMB list. Each record, with its source and retrieval date, is in
313
+ `docs/normative-verification.md`.
314
+
315
+ ### Notes
316
+
317
+ Nothing was published at the time 0.1.0 was cut: no package registry carried it
318
+ and the name was still provisional. Both changed later the same day, in 0.1.1 and
319
+ in the trademark clearance recorded in TRADEMARKS.md. This note is left as it was
320
+ written rather than edited, because a changelog that quietly updates itself stops
321
+ being a record.
@@ -6,8 +6,8 @@ This product includes software developed by the Mintmark contributors.
6
6
  Mintmark is licensed under the Apache License, Version 2.0. This NOTICE is
7
7
  informational and does not modify that license.
8
8
 
9
- Mintmark is a provisional working name. Trademark screening is not complete and
10
- the name is not frozen. See TRADEMARKS.md once published.
9
+ Mintmark is the project's settled name, frozen on 2026-08-22 after trademark
10
+ screening. See TRADEMARKS.md for what the name may and may not be used for.
11
11
 
12
12
  Third-party code or assets incorporated into Mintmark must be recorded in
13
13
  ORIGIN_AND_ATTRIBUTION.md, including any attribution or NOTICE text required
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.5
1
+ Metadata-Version: 2.4
2
2
  Name: mintmark
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Deterministic, fully synthetic, Turkish-first labeled datasets with a provenance manifest.
5
5
  Author: Mintmark contributors
6
6
  License-Expression: Apache-2.0
@@ -33,9 +33,9 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  <p align="center">
35
35
  <a href="https://github.com/lokomotifai/mintmark/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/lokomotifai/mintmark/ci.yml?branch=main&amp;style=flat-square&amp;label=CI"></a>
36
- <img alt="698 tests" src="https://img.shields.io/badge/tests-698-3C873A?style=flat-square">
36
+ <img alt="905 tests" src="https://img.shields.io/badge/tests-905-3C873A?style=flat-square">
37
37
  <img alt="18 invariants, each with a named test" src="https://img.shields.io/badge/invariants-18%20tested-3C873A?style=flat-square">
38
- <a href="https://github.com/lokomotifai/mintmark/releases/tag/v0.1.0"><img alt="Release v0.1.0" src="https://img.shields.io/badge/release-v0.1.0-3C873A?style=flat-square"></a>
38
+ <a href="https://github.com/lokomotifai/mintmark/releases/tag/v0.2.0"><img alt="Release v0.2.0" src="https://img.shields.io/badge/release-v0.2.0-3C873A?style=flat-square"></a>
39
39
  <a href="https://pypi.org/project/mintmark/"><img alt="On PyPI" src="https://img.shields.io/pypi/v/mintmark?style=flat-square&amp;label=PyPI&amp;color=3C873A"></a>
40
40
  <a href="LICENSE"><img alt="Apache-2.0 license" src="https://img.shields.io/badge/license-Apache--2.0-3B3F46?style=flat-square"></a>
41
41
  </p>
@@ -76,11 +76,10 @@ coin to say where it was made. A Mintmark dataset carries the same thing in its
76
76
  manifest, so a dataset that turns up six months later can still say what produced
77
77
  it.
78
78
 
79
- **Version 0.1, pre-release. Nothing is published to any package registry, and
80
- nothing here claims otherwise.** The name is provisional pending trademark
81
- screening. What is true today: 698 tests pass, all eighteen invariants have named
82
- tests, and the byte-level determinism claim is observed on three platforms in a
83
- single CI run rather than asserted from one.
79
+ **Published as [`mintmark`](https://pypi.org/project/mintmark/) on PyPI.** 890
80
+ tests pass, all eighteen invariants have named tests, and the byte-level
81
+ determinism claim is observed on three platforms in a single CI run rather than
82
+ asserted from one.
84
83
 
85
84
  > [!IMPORTANT]
86
85
  > **What Mintmark is not.** It is not anonymization or masking of real data; it
@@ -137,10 +136,12 @@ manifest schema: valid
137
136
  checksums: 3/3 match
138
137
  identifier policy: safe (confirmed)
139
138
  checksum-valid identifiers found: 0
139
+ coverage targets: 0 checked
140
140
  taxonomy: hushmark-tr v0.1, pin af11b31e4916
141
- label alignment: 100 documents, 81 spans
141
+ label alignment: 100 documents, 89 spans
142
142
  dataset license: CC-BY-4.0
143
143
  attribution: mintmark-example 0.1.0 reference dataset (recipe demo, seed 42), lokomotifai, licensed CC-BY-4.0
144
+ authenticity: self-consistency only; no trusted manifest digest supplied
144
145
  ```
145
146
 
146
147
  A test asserts that block against what `verify` actually prints, so this example
@@ -320,8 +321,8 @@ released on GitHub with the wheel, the source distribution, and a software bill
320
321
  of materials attached. Publication runs through trusted publishing over OIDC
321
322
  behind an approval gate, so no long-lived token exists in this repository.
322
323
 
323
- The name Mintmark is provisional pending trademark screening at TURKPATENT,
324
- EUIPO, USPTO, and WIPO. This README will say so until that changes.
324
+ The name is frozen. Trademark screening cleared on 2026-08-22, and the PyPI
325
+ namespace is held by the project.
325
326
 
326
327
  ## Community contract
327
328
 
@@ -13,9 +13,9 @@
13
13
 
14
14
  <p align="center">
15
15
  <a href="https://github.com/lokomotifai/mintmark/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/lokomotifai/mintmark/ci.yml?branch=main&amp;style=flat-square&amp;label=CI"></a>
16
- <img alt="698 tests" src="https://img.shields.io/badge/tests-698-3C873A?style=flat-square">
16
+ <img alt="905 tests" src="https://img.shields.io/badge/tests-905-3C873A?style=flat-square">
17
17
  <img alt="18 invariants, each with a named test" src="https://img.shields.io/badge/invariants-18%20tested-3C873A?style=flat-square">
18
- <a href="https://github.com/lokomotifai/mintmark/releases/tag/v0.1.0"><img alt="Release v0.1.0" src="https://img.shields.io/badge/release-v0.1.0-3C873A?style=flat-square"></a>
18
+ <a href="https://github.com/lokomotifai/mintmark/releases/tag/v0.2.0"><img alt="Release v0.2.0" src="https://img.shields.io/badge/release-v0.2.0-3C873A?style=flat-square"></a>
19
19
  <a href="https://pypi.org/project/mintmark/"><img alt="On PyPI" src="https://img.shields.io/pypi/v/mintmark?style=flat-square&amp;label=PyPI&amp;color=3C873A"></a>
20
20
  <a href="LICENSE"><img alt="Apache-2.0 license" src="https://img.shields.io/badge/license-Apache--2.0-3B3F46?style=flat-square"></a>
21
21
  </p>
@@ -56,11 +56,10 @@ coin to say where it was made. A Mintmark dataset carries the same thing in its
56
56
  manifest, so a dataset that turns up six months later can still say what produced
57
57
  it.
58
58
 
59
- **Version 0.1, pre-release. Nothing is published to any package registry, and
60
- nothing here claims otherwise.** The name is provisional pending trademark
61
- screening. What is true today: 698 tests pass, all eighteen invariants have named
62
- tests, and the byte-level determinism claim is observed on three platforms in a
63
- single CI run rather than asserted from one.
59
+ **Published as [`mintmark`](https://pypi.org/project/mintmark/) on PyPI.** 890
60
+ tests pass, all eighteen invariants have named tests, and the byte-level
61
+ determinism claim is observed on three platforms in a single CI run rather than
62
+ asserted from one.
64
63
 
65
64
  > [!IMPORTANT]
66
65
  > **What Mintmark is not.** It is not anonymization or masking of real data; it
@@ -117,10 +116,12 @@ manifest schema: valid
117
116
  checksums: 3/3 match
118
117
  identifier policy: safe (confirmed)
119
118
  checksum-valid identifiers found: 0
119
+ coverage targets: 0 checked
120
120
  taxonomy: hushmark-tr v0.1, pin af11b31e4916
121
- label alignment: 100 documents, 81 spans
121
+ label alignment: 100 documents, 89 spans
122
122
  dataset license: CC-BY-4.0
123
123
  attribution: mintmark-example 0.1.0 reference dataset (recipe demo, seed 42), lokomotifai, licensed CC-BY-4.0
124
+ authenticity: self-consistency only; no trusted manifest digest supplied
124
125
  ```
125
126
 
126
127
  A test asserts that block against what `verify` actually prints, so this example
@@ -300,8 +301,8 @@ released on GitHub with the wheel, the source distribution, and a software bill
300
301
  of materials attached. Publication runs through trusted publishing over OIDC
301
302
  behind an approval gate, so no long-lived token exists in this repository.
302
303
 
303
- The name Mintmark is provisional pending trademark screening at TURKPATENT,
304
- EUIPO, USPTO, and WIPO. This README will say so until that changes.
304
+ The name is frozen. Trademark screening cleared on 2026-08-22, and the PyPI
305
+ namespace is held by the project.
305
306
 
306
307
  ## Community contract
307
308
 
@@ -1,7 +1,7 @@
1
1
  schema_version: 1
2
2
  name: mintmark-example
3
3
  version: 0.1.0
4
- requires_core: ">=0.1,<0.2"
4
+ requires_core: ">=0.2,<0.3"
5
5
  locale: tr-TR
6
6
  allowed_identifier_policies: [safe, validator]
7
7
  description: Fixture pack for the quickstart and the test suite. Not a sector pack.
@@ -6,6 +6,4 @@ records:
6
6
  date_window:
7
7
  start: "2026-01-01T00:00:00+00:00"
8
8
  end: "2026-12-31T23:59:59+00:00"
9
- doc_mix:
10
- txn_descriptions: "1"
11
9
  special_rate: "0.05"
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["hatchling"]
2
+ requires = ["hatchling==1.31.0"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mintmark"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Deterministic, fully synthetic, Turkish-first labeled datasets with a provenance manifest."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12,<3.13"
@@ -30,6 +30,7 @@ mintmark = "mintmark.cli:main"
30
30
 
31
31
  [dependency-groups]
32
32
  dev = [
33
+ "hatchling==1.31.0",
33
34
  "pytest>=8.3,<10",
34
35
  "hypothesis>=6.112,<7",
35
36
  "ruff>=0.14,<0.17",
@@ -40,6 +41,9 @@ dev = [
40
41
  "types-jsonschema>=4.26.0.20260518",
41
42
  ]
42
43
 
44
+ [tool.uv]
45
+ required-version = "==0.12.3"
46
+
43
47
  # Package data ships with both the sdist and the wheel. tools/ and tests/ do not.
44
48
  [tool.hatch.build.targets.wheel]
45
49
  packages = ["src/mintmark"]