champollion 0.3.3 → 0.4.0
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.
- package/README.md +52 -37
- package/bin/cli.js +53 -5
- package/index.js +63 -2
- package/lib/api-key.js +17 -4
- package/lib/autofix.js +83 -36
- package/lib/bridge/method_bridge.py +15 -3
- package/lib/cards/reader.js +51 -3
- package/lib/cards/remote.js +15 -0
- package/lib/cards/search-names.js +178 -0
- package/lib/command-help.js +289 -88
- package/lib/commands/audit.js +10 -3
- package/lib/commands/card.js +583 -226
- package/lib/commands/doctor.js +54 -18
- package/lib/commands/help.js +37 -32
- package/lib/commands/init.js +1689 -87
- package/lib/commands/integrity.js +127 -40
- package/lib/commands/leaderboard.js +187 -67
- package/lib/commands/models.js +9 -2
- package/lib/commands/provenance.js +7 -2
- package/lib/commands/recommend.js +43 -14
- package/lib/commands/register-corpus.js +649 -130
- package/lib/commands/seal-corpus.js +1 -1
- package/lib/commands/status.js +564 -27
- package/lib/commands/submit.js +17 -12
- package/lib/commands/sync.js +31 -7
- package/lib/commands/tm.js +16 -10
- package/lib/commands/verify.js +27 -3
- package/lib/commands/wrap.js +63 -5
- package/lib/commands/xliff.js +135 -64
- package/lib/commercial-eligibility.js +1 -1
- package/lib/config.js +196 -14
- package/lib/content-estimate.js +96 -0
- package/lib/content-refusals.js +270 -0
- package/lib/content-review.js +372 -0
- package/lib/content-sync.js +1127 -344
- package/lib/content.js +94 -7
- package/lib/corpus-registration.mjs +197 -38
- package/lib/cost-label.js +29 -0
- package/lib/cost-report.js +726 -78
- package/lib/diff.js +38 -4
- package/lib/docusaurus-sync.js +965 -253
- package/lib/edit-distance.js +31 -0
- package/lib/fallback.js +964 -0
- package/lib/file-scope.js +106 -0
- package/lib/flatten.js +80 -3
- package/lib/flutter-locales.js +124 -0
- package/lib/format.js +266 -12
- package/lib/hash.js +146 -21
- package/lib/icu-structure.js +929 -0
- package/lib/integrity.js +223 -75
- package/lib/language-pair.js +157 -0
- package/lib/lint.js +78 -16
- package/lib/local-only-marks.js +106 -0
- package/lib/locale-layout.js +1103 -0
- package/lib/locale-state.js +571 -0
- package/lib/methods/anthropic.js +5 -0
- package/lib/methods/apertium.js +6 -3
- package/lib/methods/api.js +138 -25
- package/lib/methods/base.js +17 -0
- package/lib/methods/coaching-data.js +153 -0
- package/lib/methods/content-separator.js +43 -0
- package/lib/methods/deepl.js +1 -1
- package/lib/methods/direct-llm.js +252 -103
- package/lib/methods/external.js +146 -63
- package/lib/methods/gemini.js +1 -0
- package/lib/methods/google-translate.js +1 -0
- package/lib/methods/http-utils.js +41 -0
- package/lib/methods/libretranslate.js +7 -2
- package/lib/methods/llm-coached.js +68 -128
- package/lib/methods/llm.js +80 -31
- package/lib/methods/local.js +93 -10
- package/lib/methods/microsoft-translator.js +1 -2
- package/lib/methods/openai.js +4 -2
- package/lib/methods/openrouter-client.js +20 -19
- package/lib/methods/openrouter-pricing.js +150 -13
- package/lib/methods/prompt-methods.js +20 -0
- package/lib/methods/provider-pricing.js +42 -1
- package/lib/methods/request-capture.js +104 -0
- package/lib/methods/tilde.js +1 -1
- package/lib/methods/translated.js +1 -2
- package/lib/missing-key.js +93 -0
- package/lib/models.js +11 -0
- package/lib/name-rules.js +32 -0
- package/lib/named-keys.js +172 -0
- package/lib/no-translate.js +4 -3
- package/lib/output.js +160 -19
- package/lib/pairs.js +586 -30
- package/lib/placeholders.js +394 -0
- package/lib/plugins.js +8 -0
- package/lib/plural-gap-redo.js +109 -0
- package/lib/plurals.js +323 -0
- package/lib/po.js +1187 -0
- package/lib/public-catalogue.js +74 -0
- package/lib/recommend.js +527 -32
- package/lib/redo.js +95 -0
- package/lib/refusal-category.js +44 -0
- package/lib/registers.js +255 -11
- package/lib/repair-script.js +20 -13
- package/lib/scripts.js +193 -106
- package/lib/seal.mjs +6 -5
- package/lib/sealed-qualifier.mjs +2 -2
- package/lib/segment.js +2 -1
- package/lib/seo.js +19 -9
- package/lib/serve.js +43 -6
- package/lib/shared-output-seed.js +164 -0
- package/lib/source-contexts.js +39 -0
- package/lib/submit.mjs +57 -5
- package/lib/sync.js +2923 -474
- package/lib/terminology.js +13 -4
- package/lib/tm-evict.js +179 -0
- package/lib/tm-seed.js +5 -2
- package/lib/tm.js +818 -36
- package/lib/translate-pair.js +639 -34
- package/lib/translate.js +78 -5
- package/lib/types.js +22 -3
- package/lib/validate.js +880 -17
- package/lib/verify.js +1296 -104
- package/lib/watch.js +32 -13
- package/lib/xliff.js +44 -3
- package/package.json +3 -2
- package/shared/CORPORA-CARDS.md +2 -0
- package/shared/DATA-SOVEREIGNTY.md +19 -20
- package/shared/LANGUAGE-CARD-FIELDS.md +1 -1
- package/shared/cards-fallback.json +1 -1
- package/shared/catalogue/card-config.json +1 -1
- package/shared/curated-orthography-conventions.json +26 -8
- package/shared/docent/faq.en.json +14 -16
- package/shared/docent/system-prompt.md +17 -19
- package/shared/explainers/tc-features.json +15 -15
- package/shared/gettext-plural-forms.json +45 -0
- package/shared/human-services.json +1 -1
- package/shared/method-registry.json +2 -0
- package/shared/metric-registry.json +96 -18
- package/shared/schemas/champollion-plugin.schema.json +4 -0
- package/shared/schemas/corpora-card.schema.json +20 -10
- package/shared/schemas/human-services.schema.json +2 -2
- package/shared/schemas/language-card.schema.json +1 -1
- package/shared/schemas/method-card.schema.json +1 -1
- package/shared/schemas/method-index-record.schema.json +67 -0
- package/shared/schemas/method-registry.schema.json +4 -0
- package/shared/schemas/metric-registry.schema.json +55 -1
- package/shared/docent/corpus.json +0 -11333
package/lib/watch.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import fs from 'node:fs';
|
|
21
21
|
import path from 'node:path';
|
|
22
22
|
import { resolveConfig } from './config.js';
|
|
23
|
-
import {
|
|
23
|
+
import { discoverLocaleLayout } from './locale-layout.js';
|
|
24
24
|
import { runSync } from './sync.js';
|
|
25
25
|
import { output } from './output.js';
|
|
26
26
|
|
|
@@ -53,13 +53,27 @@ import { output } from './output.js';
|
|
|
53
53
|
async function startWatch(options = {}) {
|
|
54
54
|
const { cwd = process.cwd(), cliArgs = {} } = options;
|
|
55
55
|
const config = resolveConfig(cliArgs, cwd);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
// Every source file of the layout is watched: one for a flat project,
|
|
57
|
+
// one per namespace for a folder-per-locale project (en/common.json,
|
|
58
|
+
// en/admin.json, …). Docusaurus watches its source locale's JSON the
|
|
59
|
+
// same way the flat lane always did (i18n/<source>.json does not exist
|
|
60
|
+
// there, so it keeps the historical single-path behaviour).
|
|
61
|
+
let sourcePaths;
|
|
62
|
+
let sourceLabel;
|
|
63
|
+
if (config.format === 'docusaurus') {
|
|
64
|
+
sourcePaths = [path.join(config.localesDir, `${config.inputLocale}.json`)];
|
|
65
|
+
sourceLabel = `${config.inputLocale}.json`;
|
|
66
|
+
} else {
|
|
67
|
+
const layout = discoverLocaleLayout(config, { cwd });
|
|
68
|
+
sourcePaths = layout.sourceFiles.map(f => f.path);
|
|
69
|
+
sourceLabel = layout.namespaced
|
|
70
|
+
? `${layout.sourceFiles.length} source file(s) (${layout.display})`
|
|
71
|
+
: layout.sourceFiles[0].rel;
|
|
72
|
+
if (sourcePaths.length === 0) {
|
|
73
|
+
throw new Error(`No ${layout.format} source files found for ${config.inputLocale} (${layout.display}) — nothing to watch.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const sourceFile = sourceLabel;
|
|
63
77
|
|
|
64
78
|
output.info(`Watching ${sourceFile} for changes...`);
|
|
65
79
|
|
|
@@ -101,9 +115,11 @@ async function startWatch(options = {}) {
|
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
117
|
|
|
104
|
-
// Watch the source file using stat polling (fs.watchFile).
|
|
105
|
-
// On change, debounce for 500ms then sync.
|
|
106
|
-
|
|
118
|
+
// Watch the source file(s) using stat polling (fs.watchFile).
|
|
119
|
+
// On change, debounce for 500ms then sync. A namespace file ADDED after
|
|
120
|
+
// the watcher started is picked up by the next sync, but is not itself
|
|
121
|
+
// watched until watch mode restarts.
|
|
122
|
+
const onChange = (curr, prev) => {
|
|
107
123
|
// Only react to actual content changes (mtime changed)
|
|
108
124
|
if (curr.mtimeMs === prev.mtimeMs) return;
|
|
109
125
|
|
|
@@ -120,7 +136,10 @@ async function startWatch(options = {}) {
|
|
|
120
136
|
// inside doSync() and logged, never thrown.
|
|
121
137
|
doSync();
|
|
122
138
|
}, 500);
|
|
123
|
-
}
|
|
139
|
+
};
|
|
140
|
+
for (const sourcePath of sourcePaths) {
|
|
141
|
+
fs.watchFile(sourcePath, { interval: 500 }, onChange);
|
|
142
|
+
}
|
|
124
143
|
|
|
125
144
|
// Signal that the watcher is active and ready for file changes.
|
|
126
145
|
// Tests use this line to know when it's safe to modify the source file.
|
|
@@ -135,7 +154,7 @@ async function startWatch(options = {}) {
|
|
|
135
154
|
// if startWatch were ever called more than once in the same process.
|
|
136
155
|
process.once('SIGINT', () => {
|
|
137
156
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
138
|
-
fs.unwatchFile(sourcePath);
|
|
157
|
+
for (const sourcePath of sourcePaths) fs.unwatchFile(sourcePath);
|
|
139
158
|
resolve(); // Allow the promise to resolve so cleanup can happen
|
|
140
159
|
process.exit(0);
|
|
141
160
|
});
|
package/lib/xliff.js
CHANGED
|
@@ -20,6 +20,15 @@
|
|
|
20
20
|
* third-party tools with extensions, inline markup, etc. If a user
|
|
21
21
|
* imports XLIFF from memoQ, we extract <target> text and ignore the rest.
|
|
22
22
|
*
|
|
23
|
+
* UNIT IDS are locale keys. A gettext key with a context is
|
|
24
|
+
* `msgctxt + U+0004 + msgid` (lib/po.js), and XML 1.0 cannot carry U+0004
|
|
25
|
+
* at all — not even as a character reference — so the id writes it as "␄"
|
|
26
|
+
* (U+2404, the visible symbol for that character, the same form reports
|
|
27
|
+
* and `--force-keys` use) and import maps it back. Newlines, tabs and CRs
|
|
28
|
+
* in an id (multi-line msgids) are written as character references: a
|
|
29
|
+
* literal newline in an attribute is turned into a space by every XML
|
|
30
|
+
* parser, which would silently rename the key in a CAT tool round trip.
|
|
31
|
+
*
|
|
23
32
|
* ZERO DEPENDENCIES. Uses regex-based XML parsing because:
|
|
24
33
|
* 1. Our XLIFF output is predictable and well-formed
|
|
25
34
|
* 2. We only need to extract source/target text from <trans-unit> elements
|
|
@@ -66,7 +75,7 @@ function exportXLIFF({ sourceLocale, targetLocale, sourceFlat, targetFlat, origi
|
|
|
66
75
|
const body = exempt ? sourceValue : (hasTarget ? targetValue : '');
|
|
67
76
|
|
|
68
77
|
units.push(
|
|
69
|
-
` <trans-unit id="${
|
|
78
|
+
` <trans-unit id="${encodeUnitId(key)}"${exempt ? ' translate="no"' : ''} xml:space="preserve">` +
|
|
70
79
|
`\n <source>${escapeXML(sourceValue)}</source>` +
|
|
71
80
|
`\n <target state="${state}">${escapeXML(body)}</target>` +
|
|
72
81
|
`\n </trans-unit>`
|
|
@@ -125,7 +134,7 @@ function importXLIFF(xliffString) {
|
|
|
125
134
|
let match;
|
|
126
135
|
|
|
127
136
|
while ((match = unitPattern.exec(xliffString)) !== null) {
|
|
128
|
-
const unitId =
|
|
137
|
+
const unitId = decodeUnitId(match[1]);
|
|
129
138
|
const unitContent = match[0];
|
|
130
139
|
|
|
131
140
|
// Extract target content (if present and non-empty)
|
|
@@ -157,14 +166,44 @@ function escapeXML(str) {
|
|
|
157
166
|
.replace(/'/g, ''');
|
|
158
167
|
}
|
|
159
168
|
|
|
169
|
+
/** gettext's msgctxt separator, and how an XLIFF id writes it. */
|
|
170
|
+
const CONTEXT_SEPARATOR = '\u0004';
|
|
171
|
+
const CONTEXT_SEPARATOR_VISIBLE = '\u2404';
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* A locale key as an XLIFF unit id (see "UNIT IDS" above).
|
|
175
|
+
*
|
|
176
|
+
* @param {string} key
|
|
177
|
+
* @returns {string} Attribute-safe id
|
|
178
|
+
*/
|
|
179
|
+
function encodeUnitId(key) {
|
|
180
|
+
return escapeXML(key.split(CONTEXT_SEPARATOR).join(CONTEXT_SEPARATOR_VISIBLE))
|
|
181
|
+
.replace(/\n/g, ' ')
|
|
182
|
+
.replace(/\r/g, ' ')
|
|
183
|
+
.replace(/\t/g, '	');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The locale key an XLIFF unit id names.
|
|
188
|
+
*
|
|
189
|
+
* @param {string} raw - Attribute value as found in the file
|
|
190
|
+
* @returns {string}
|
|
191
|
+
*/
|
|
192
|
+
function decodeUnitId(raw) {
|
|
193
|
+
return unescapeXML(raw).split(CONTEXT_SEPARATOR_VISIBLE).join(CONTEXT_SEPARATOR);
|
|
194
|
+
}
|
|
195
|
+
|
|
160
196
|
/**
|
|
161
|
-
* Unescape XML entities back to raw characters
|
|
197
|
+
* Unescape XML entities back to raw characters (named entities and
|
|
198
|
+
* numeric character references).
|
|
162
199
|
*
|
|
163
200
|
* @param {string} str - XML-escaped string
|
|
164
201
|
* @returns {string} Raw string
|
|
165
202
|
*/
|
|
166
203
|
function unescapeXML(str) {
|
|
167
204
|
return str
|
|
205
|
+
.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))
|
|
206
|
+
.replace(/&#(\d+);/g, (_, dec) => String.fromCodePoint(Number(dec)))
|
|
168
207
|
.replace(/'/g, "'")
|
|
169
208
|
.replace(/"/g, '"')
|
|
170
209
|
.replace(/>/g, '>')
|
|
@@ -181,4 +220,6 @@ export {
|
|
|
181
220
|
importXLIFF,
|
|
182
221
|
escapeXML,
|
|
183
222
|
unescapeXML,
|
|
223
|
+
encodeUnitId,
|
|
224
|
+
decodeUnitId,
|
|
184
225
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "champollion",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Research-grade translation engine for i18n projects. Pluggable methods, per-pair quality tiers, and deterministic script converters. Supports JSON (next-intl, i18next), TOML, and YAML (Hugo).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"language-subtag-registry": "^0.4.2"
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
|
-
"@translated/lara": "^1.12.1"
|
|
91
|
+
"@translated/lara": "^1.12.1",
|
|
92
|
+
"cree-sro-syllabics": "2021.6.8"
|
|
92
93
|
}
|
|
93
94
|
}
|
package/shared/CORPORA-CARDS.md
CHANGED
|
@@ -54,6 +54,8 @@ A pair-specific, community-curated dataset used for official Champollion evaluat
|
|
|
54
54
|
|
|
55
55
|
The `eval-` prefix makes it instantly clear this is a benchmark, not just a dataset catalogue entry.
|
|
56
56
|
|
|
57
|
+
The `{segment}` part is optional: the schema's id pattern only requires `eval-`/`ref-` plus lower-case kebab-case, and some cards carry none (`eval-in22-gen-v1`). Cards written by `champollion register-corpus` are `eval-{src}-{tgt}-{name}[-{role}]-v1`: `{name}` is the slugged `--name` (the publisher only when the name has no a–z/0–9 letters), and `{role}` (`test` / `dev` / `train`) appears only when the author passed `--role`. No role is ever guessed, and an id already registered is never re-derived.
|
|
58
|
+
|
|
57
59
|
---
|
|
58
60
|
|
|
59
61
|
## Official Champollion Evaluation
|
|
@@ -39,19 +39,19 @@ Each sovereignty-related field maps to one or more external standards. The table
|
|
|
39
39
|
|
|
40
40
|
| Field / Concept | Primary Standard | Standard URL | Relationship |
|
|
41
41
|
|---|---|---|---|
|
|
42
|
-
| `sovereignty.frameworks` |
|
|
43
|
-
| `sovereignty.governanceOrg` |
|
|
44
|
-
| `sovereignty.custodian` |
|
|
45
|
-
| `sovereignty.consentModel` |
|
|
42
|
+
| `sovereignty.frameworks` | CARE, Te Mana Raraunga, FAIR, IEEE 2890, community ownership-and-control assertions | See individual URLs below | Records which frameworks have been **explicitly invoked** by the governing body |
|
|
43
|
+
| `sovereignty.governanceOrg` | Community ownership | — | Who owns the data |
|
|
44
|
+
| `sovereignty.custodian` | Community possession | — | Who physically holds the data |
|
|
45
|
+
| `sovereignty.consentModel` | Community control, CARE Authority | [https://www.gida-global.org/care](https://www.gida-global.org/care) | Who controls access — maps to CARE's Authority to Control principle |
|
|
46
46
|
| `sovereignty.tkLabels[]` | Local Contexts TK/BC Labels | [https://localcontexts.org/](https://localcontexts.org/) | Community-applied labels from the Local Contexts Hub |
|
|
47
47
|
| `usageRestrictions.training` | DUO (Data Use Ontology), ODRL | [DUO](https://github.com/EBISPOT/DUO), [ODRL](https://www.w3.org/TR/odrl-model/) | `prohibited-by-license` maps to DUO:0000004 (no general methods research) and ODRL `odrl:prohibition`. `prohibited-by-community` maps to a governance assertion (no DUO equivalent — DUO is license-derived) |
|
|
48
48
|
| `usageRestrictions.commercialUse` | DUO:0000018 (not for profit), ODRL | [DUO](https://github.com/EBISPOT/DUO), [ODRL](https://www.w3.org/TR/odrl-model/) | `prohibited-by-license` maps to DUO:0000018 and ODRL `odrl:prohibition` with `odrl:commercialize` action |
|
|
49
49
|
| `usageRestrictions.redistribution` | ODRL `odrl:distribute` | [ODRL](https://www.w3.org/TR/odrl-model/) | Maps to an ODRL permission/prohibition on the `odrl:distribute` action |
|
|
50
50
|
| `usageRestrictions.communityNotes` | CARE Ethics | [https://www.gida-global.org/care](https://www.gida-global.org/care) | Maps to CARE's Ethics principle — ensuring legitimate concerns are surfaced |
|
|
51
51
|
| `doNotTrain` | IEEE 2890 | No public URL (IEEE standard, paywall) | Methodological constraint for evaluation data; IEEE 2890 §7.4 recommends flagging datasets not intended for model training |
|
|
52
|
-
| `stewardship.authorizationModel` |
|
|
53
|
-
| `submission.transfer.*` |
|
|
54
|
-
| `submission.admissibility.selfHostable` |
|
|
52
|
+
| `stewardship.authorizationModel` | Community control | — | Community controls how evaluation access is granted |
|
|
53
|
+
| `submission.transfer.*` | Community ownership + possession, CARE Collective Benefit | [CARE](https://www.gida-global.org/care) | Transfer provisions mean the community owns and possesses the method. Revenue model maps to CARE Collective Benefit |
|
|
54
|
+
| `submission.admissibility.selfHostable` | Community possession | — | If the community can't run it independently, they don't possess it |
|
|
55
55
|
|
|
56
56
|
### Standard References
|
|
57
57
|
|
|
@@ -61,7 +61,6 @@ Each sovereignty-related field maps to one or more external standards. The table
|
|
|
61
61
|
| DUO | Data Use Ontology | [https://github.com/EBISPOT/DUO](https://github.com/EBISPOT/DUO) |
|
|
62
62
|
| Local Contexts | TK and BC Labels | [https://localcontexts.org/](https://localcontexts.org/) |
|
|
63
63
|
| CARE | Collective Benefit, Authority to Control, Responsibility, Ethics | [https://www.gida-global.org/care](https://www.gida-global.org/care) |
|
|
64
|
-
| OCAP® | Ownership, Control, Access, Possession | [https://fnigc.ca/ocap-training/](https://fnigc.ca/ocap-training/) |
|
|
65
64
|
| IEEE 2890 | IEEE Standard for Recommended Practice for Provenance of Datasets | IEEE (paywall; no stable public URL) |
|
|
66
65
|
| Te Mana Raraunga | Māori Data Sovereignty Network | [https://www.temanararaunga.maori.nz/](https://www.temanararaunga.maori.nz/) |
|
|
67
66
|
| FAIR | Findable, Accessible, Interoperable, Reusable | [https://www.go-fair.org/fair-principles/](https://www.go-fair.org/fair-principles/) |
|
|
@@ -108,7 +107,7 @@ The `sovereignty` object records governance structures that actually exist for t
|
|
|
108
107
|
| Field | Type | Allowed Values | Description | When to use `null` |
|
|
109
108
|
|---|---|---|---|---|
|
|
110
109
|
| `sovereignty` | `object \| null` | — | Container for governance metadata. | No governance body has been identified. No frameworks have been invoked. No labels have been applied. |
|
|
111
|
-
| `.frameworks` | `array` of `string` | `"
|
|
110
|
+
| `.frameworks` | `array` of `string` | `"community-ownership-control"`, `"CARE"`, `"Te-Mana-Raraunga"`, `"FAIR"`, `"IEEE-2890"` | Data sovereignty frameworks the data creators or governing body have **explicitly invoked**. Only list frameworks where there is documented evidence of adoption. | *(Field is an array — use `[]` if sovereignty object exists but no frameworks have been invoked. But if no sovereignty object at all, the whole object is null.)* |
|
|
112
111
|
| `.governanceOrg` | `string \| null` | Free text | Organization or body with governance authority. For Indigenous-governed corpora, this is the language trust, tribal council, or delegated body. | No governance body has been identified or established. |
|
|
113
112
|
| `.custodian` | `string \| null` | Free text | Who physically holds the data. Distinct from `governanceOrg` — a university may be custodian while a community is the governance authority. | Custodian is the same as `source.publisher` (no need to repeat). |
|
|
114
113
|
| `.consentModel` | `string \| null` | `"per-submission"`, `"blanket"`, `"open-access"` | How consent is structured for use of this data in method evaluation. | No consent model has been established. |
|
|
@@ -123,7 +122,7 @@ The `sovereignty` object records governance structures that actually exist for t
|
|
|
123
122
|
```json
|
|
124
123
|
{
|
|
125
124
|
"sovereignty": {
|
|
126
|
-
"frameworks": ["
|
|
125
|
+
"frameworks": ["community-ownership-control", "CARE"],
|
|
127
126
|
"governanceOrg": "Plains Cree Language Trust (hypothetical)",
|
|
128
127
|
"custodian": "University of Alberta — ALTLab",
|
|
129
128
|
"consentModel": "per-submission",
|
|
@@ -264,13 +263,13 @@ The `submission` field (§7) defines what happens when a method is accepted: wha
|
|
|
264
263
|
|
|
265
264
|
## 7. Admissibility Rules
|
|
266
265
|
|
|
267
|
-
The `submission.admissibility` fields define what methods are eligible for prize evaluation. These constraints are technical, not arbitrary — they flow directly from
|
|
266
|
+
The `submission.admissibility` fields define what methods are eligible for prize evaluation. These constraints are technical, not arbitrary — they flow directly from the community-possession requirement (the community must be able to hold and run the method itself) and the air-gapped sandbox architecture.
|
|
268
267
|
|
|
269
268
|
### Why Coached API Calls Are Inadmissible
|
|
270
269
|
|
|
271
270
|
A "coached API call" is a method that wraps a third-party API (e.g., GPT-4, Google Translate) with prompt engineering. These are inadmissible for prize evaluation because:
|
|
272
271
|
|
|
273
|
-
1. **
|
|
272
|
+
1. **Community-possession violation.** The community cannot possess a method that depends on someone else's API. When the API key expires, the method dies. The community doesn't control the model, its weights, or its availability.
|
|
274
273
|
|
|
275
274
|
2. **Non-reproducible.** API providers change models, pricing, and availability without notice. A score measured today may not be reproducible tomorrow.
|
|
276
275
|
|
|
@@ -286,9 +285,9 @@ A "coached API call" is a method that wraps a third-party API (e.g., GPT-4, Goog
|
|
|
286
285
|
- No license-restricted runtime dependencies that the community cannot independently obtain
|
|
287
286
|
- The community can inspect, modify, and deploy the method on their own hardware
|
|
288
287
|
|
|
289
|
-
###
|
|
288
|
+
### Community-Possession Logic
|
|
290
289
|
|
|
291
|
-
The
|
|
290
|
+
The community-possession principle states that the community must physically hold the data and tools. In the context of prize evaluation:
|
|
292
291
|
|
|
293
292
|
| What | Possession requirement |
|
|
294
293
|
|---|---|
|
|
@@ -311,15 +310,15 @@ The evaluation sandbox operates with no network access:
|
|
|
311
310
|
|---|---|---|
|
|
312
311
|
| `selfHostable` | `boolean` | Method must run on community infrastructure without any third-party dependencies. |
|
|
313
312
|
| `inadmissible` | `array` of `string` | Explicitly inadmissible method types. e.g., `"coached-api-calls"`, `"proprietary-api-wrappers"`, `"external-api-dependencies"`. |
|
|
314
|
-
| `notes` | `string \| null` | Rationale for admissibility constraints. Should reference
|
|
313
|
+
| `notes` | `string \| null` | Rationale for admissibility constraints. Should reference community possession and the air-gapped sandbox architecture. |
|
|
315
314
|
|
|
316
315
|
### `submission.transfer` Fields — What the Community Gets
|
|
317
316
|
|
|
318
|
-
| Field | Type | Description |
|
|
317
|
+
| Field | Type | Description | Sovereignty/CARE mapping |
|
|
319
318
|
|---|---|---|---|
|
|
320
|
-
| `sourceCode` | `boolean` | Source code ownership transfers to governance org |
|
|
321
|
-
| `modelWeights` | `boolean` | Trained model weights transfer to governance org |
|
|
322
|
-
| `deploymentRights` | `boolean` | Exclusive deployment rights transfer to governance org |
|
|
319
|
+
| `sourceCode` | `boolean` | Source code ownership transfers to governance org | Community ownership + possession |
|
|
320
|
+
| `modelWeights` | `boolean` | Trained model weights transfer to governance org | Community possession |
|
|
321
|
+
| `deploymentRights` | `boolean` | Exclusive deployment rights transfer to governance org | Community control |
|
|
323
322
|
| `revenueModel` | `string \| null` | Community-set terms for any commercial deployment, held by the governance org (e.g., `"commercial use by written permission only"`) — Champollion is non-commercial and takes no share | CARE Collective Benefit |
|
|
324
323
|
|
|
325
324
|
### `submission.retained` Fields — What the Researcher Keeps
|
|
@@ -438,7 +437,7 @@ These are documented mistakes to avoid when populating sovereignty fields. Each
|
|
|
438
437
|
|
|
439
438
|
### Don't derive sovereignty from vitality
|
|
440
439
|
|
|
441
|
-
**Wrong:** Seeing that a language is `"severely-endangered"` in `vitality.unescoStatus` and automatically populating
|
|
440
|
+
**Wrong:** Seeing that a language is `"severely-endangered"` in `vitality.unescoStatus` and automatically populating sovereignty frameworks, TK Labels, or consent models.
|
|
442
441
|
|
|
443
442
|
**Right:** Sovereignty fields are populated from **documented evidence of governance adoption** — a formal resolution, a published data governance policy, or a registered Local Contexts Hub project. Endangerment status and sovereignty are orthogonal. A safe, widely-spoken language may have strong data sovereignty frameworks (e.g., Māori → Te Mana Raraunga). A critically endangered language may have no formal governance body.
|
|
444
443
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
This document describes every field in the Champollion language card schema. For each field you will find the JSON key, type, data source(s), a plain-English description, and a real value from an existing card.
|
|
9
9
|
|
|
10
|
-
For
|
|
10
|
+
For provenance rules and how disagreeing sources are shown, see the [language card specification](https://champollion.dev/docs/reference/language-card-spec).
|
|
11
11
|
For license obligations see [ATTRIBUTION.md](./ATTRIBUTION.md).
|
|
12
12
|
|
|
13
13
|
---
|