@aikdna/kdna-studio-core 1.5.3 → 1.5.5

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 CHANGED
@@ -1,17 +1,34 @@
1
1
  # KDNA Studio Core
2
2
 
3
- **KDNA Studio Core is the judgment asset refinery.** It turns scattered notes, documents, works, and feedback into loadable .kdna judgment assets — not by compressing content, but by distilling the stable judgment patterns embedded within it.
3
+ **KDNA Studio Core is the judgment asset refinery.** It turns scattered notes, documents, works, and feedback into loadable `.kdna` judgment assets — not by compressing content, but by distilling stable judgment patterns into a declared domain and loading scope.
4
4
 
5
- AI may propose judgment candidates from content analysis. Humans must confirm judgment. Only human-locked judgment can compile into KDNA.
5
+ Studio Core is part of the official authoring toolchain. It can record human review, Human Lock, signatures, and release evidence as provenance signals, but those signals are not KDNA Core v1 format-validity requirements and they do not make content officially endorsed, certified, or universally safe.
6
6
 
7
- Open-source Studio-compatible authoring kernel for creating trusted `.kdna` assets — JS/npm package. Supports two authoring paths: interview-first (expert self-expression) and distillation-first (pattern extraction from existing content). Both end with Human Judgment Lock.
7
+ Open-source Studio-compatible authoring kernel for creating reviewable `.kdna` assets — JS/npm package. Supports two authoring paths: interview-first (direct expression) and distillation-first (pattern extraction from existing content). Both end with a canonical KDNA Core v1 runtime export.
8
8
 
9
- **KDNA Studio Core is the JS authoring kernel.** It is not a UI tool and not a CLI package. It is a pure-logic engine for creating KDNA judgment cards, Human Locks, compiler output, and authoring provenance from JavaScript applications and Studio-compatible tools.
9
+ **KDNA Studio Core is the JS authoring kernel.** It is not a UI tool and not a CLI package. It is a pure-logic engine for creating KDNA judgment cards, optional provenance records, compiler output, and runtime `.kdna` exports from JavaScript applications and Studio-compatible tools.
10
10
 
11
- A `.kdna` asset is not created by writing JSON files. It is compiled by a
12
- Studio-compatible authoring pipeline that performs human confirmation,
13
- validation, canonicalization, identity generation, digest computation, signing,
14
- optional encryption, and provenance recording.
11
+ A `.kdna` asset is not a public source JSON folder. Studio-compatible tooling
12
+ uses a project workspace for authoring, review, and audit, then exports the
13
+ canonical KDNA Core v1 runtime container. Human confirmation, Human Lock,
14
+ signing, optional encryption, and release evidence are provenance layers, not
15
+ format-validity requirements.
16
+
17
+ Studio Core distinguishes authoring compile output from runtime distribution
18
+ output. Authoring compile output may include source entries such as
19
+ `KDNA_Core.json` and `KDNA_Patterns.json` for audit and review. Runtime export
20
+ must produce the canonical KDNA Core v1 distribution shape:
21
+
22
+ ```text
23
+ mimetype
24
+ kdna.json
25
+ payload.kdnab
26
+ checksums.json
27
+ ```
28
+
29
+ Runtime export must validate with `@aikdna/kdna-core` and must plan through the
30
+ LoadPlan contract in `aikdna/kdna`. Studio products must not create app-private
31
+ `.kdna` shapes that Chat or CLI cannot inspect, validate, or plan-load.
15
32
 
16
33
  **Hard boundary:** Optional encryption, when supported, MUST be represented as
17
34
  protected entries inside the `.kdna` container (RFC-0008). App-private encrypted
@@ -21,8 +38,8 @@ conforming KDNA runtime assets.
21
38
  | Library | Language | Role |
22
39
  |---------|----------|------|
23
40
  | `@aikdna/kdna-cli` | JS/npm | **Operate** KDNA — install, verify, load, compare, publish |
24
- | **`@aikdna/kdna-studio-core`** | JS/npm | **Authoring kernel** — project model, cards, Human Lock, compiler, provenance |
25
- | `@aikdna/kdna-studio-cli` | JS/npm | **Create via CLI** — `kdna-studio` create, compile, export |
41
+ | **`@aikdna/kdna-studio-core`** | JS/npm | **Authoring kernel** — project model, cards, review/provenance, compiler, runtime export |
42
+ | `@aikdna/kdna-studio-cli` | JS/npm | **Create via CLI** — `kdna-studio` create, review, export |
26
43
  | `@aikdna/kdna-core` | JS/npm | **Use** KDNA — load, validate, format |
27
44
 
28
45
  ## What it does
@@ -33,14 +50,16 @@ conforming KDNA runtime assets.
33
50
  - **Evidence Relevance** — classify source material as relevant, weakly relevant, out-of-scope, or split-domain before distillation
34
51
  - **Scope Gate** — mark candidates with `scope_fit`, relevance score, and suggested split domain before they can become cards
35
52
  - **Judgment Cards** — 8 card types: axiom, ontology, stance, framework, misunderstanding, self_check, banned_term, terminology
36
- - **Human Lock** — AI proposes, human confirms. Only locked cards compile.
53
+ - **Review and provenance** — AI may propose candidates; projects can record human confirmation, Human Lock, signatures, and release evidence when needed.
37
54
  - **Authoring Provenance** — every compiled manifest records Studio-compatible
38
- compiler metadata, project digest, Human Lock count, and confirmation status.
39
- - **Asset Build Reports** — every compile emits build, provenance, Human Lock,
55
+ compiler metadata, project digest, review counts, and confirmation status.
56
+ - **Asset Build Reports** — every compile emits build, provenance, review,
40
57
  quality gate, eval, and receipt artifacts for audit.
41
58
  - **Feynman Restatement** — verify understanding, not just agreement
42
59
  - **Quality Gates** — readiness check: draft → structurally_ready → judgment_ready → publish_ready
43
60
  - **Compiler** — locked cards → `KDNA_Core.json` + `KDNA_Patterns.json`
61
+ - **Runtime Export** — compiled judgment → canonical `mimetype` +
62
+ `kdna.json` + `payload.kdnab` + `checksums.json`
44
63
  - **Test Lab** — A/B comparison (No KDNA vs Best Prompt vs KDNA)
45
64
  - **Provenance** — content fingerprinting, build tracking, audit trail
46
65
 
@@ -54,14 +73,14 @@ conforming KDNA runtime assets.
54
73
  ## Authoring Flow
55
74
 
56
75
  ```
57
- Evidence Room → Judgment Cards → Human Lock → Quality Gate → Compile → Validate → Export
76
+ Evidence Room → Judgment Cards → Review/Provenance → Quality Gate → Compile → Validate → Export
58
77
  ```
59
78
 
60
79
  For distillation-first authoring, the flow starts with an explicit target:
61
80
 
62
81
  ```
63
82
  Declare Domain + Scope → Import Evidence → Classify Relevance → Distill Candidates
64
- → Scope Gate → Human Review → Promote to Cards → Human Lock → Compile → Export
83
+ → Scope Gate → Review → Promote to Cards → Provenance → Compile → Export
65
84
  ```
66
85
 
67
86
  A single `.kdna` asset should stay scoped to one domain and loading condition. If a task needs several judgment domains, create multiple domain assets and compose them through a KDNA Cluster rather than making one broad file.
@@ -99,9 +118,9 @@ kdna-studio card add my_domain axiom \
99
118
  --field does_not_apply_when='["Out of scope"]' \
100
119
  --field failure_risk="What could go wrong"
101
120
  kdna-studio card approve my_domain <card-id> --by expert --statement "I confirm this judgment."
102
- kdna-studio export my_domain --out dist/my_domain.kdna --sign
103
- kdna verify dist/my_domain.kdna --judgment
104
- kdna publish dist/my_domain.kdna
121
+ kdna-studio export my_domain --format v1 --out dist/my_domain.kdna
122
+ kdna validate dist/my_domain.kdna
123
+ kdna plan-load dist/my_domain.kdna
105
124
  ```
106
125
 
107
126
  ## Quick Start
@@ -110,6 +129,8 @@ kdna publish dist/my_domain.kdna
110
129
  const {
111
130
  project: projectApi,
112
131
  cards: cardApi,
132
+ compile,
133
+ exportRuntime,
113
134
  distillation
114
135
  } = require('@aikdna/kdna-studio-core');
115
136
 
@@ -141,7 +162,7 @@ const card = cardApi.createCard('axiom', {
141
162
  });
142
163
  project.cards.push(card);
143
164
 
144
- // 3. Human Lock
165
+ // 3. Optional review provenance for this Studio project
145
166
  const locked = cardApi.lockCard(card, {
146
167
  by: 'writer_001',
147
168
  statement: 'This represents my professional writing judgment.',
@@ -151,12 +172,48 @@ const locked = cardApi.lockCard(card, {
151
172
  // 4. Check readiness
152
173
  const gate = projectApi.checkHumanLockGate(project);
153
174
  if (!gate.blocked) {
154
- // 5. Export
155
- const json = projectApi.exportProject(project);
156
- console.log('Ready to publish');
175
+ // 5. Compile and runtime-export
176
+ const compiled = compile.compileDomain(project, { strictAuthority: false });
177
+ const runtimeAsset = exportRuntime.exportRuntimeAsset(project, { compiled });
178
+ console.log(Object.keys(runtimeAsset.files));
157
179
  }
158
180
  ```
159
181
 
182
+ ## Runtime Export Contract
183
+
184
+ `compile.compileDomain(project)` is an authoring compile step. It returns source
185
+ and evidence artifacts for review, audit, and reports. It is not itself the
186
+ runtime distribution contract.
187
+
188
+ Use `exportRuntime.exportRuntimeAsset(project)` to produce a KDNA Core v1
189
+ runtime source directory payload:
190
+
191
+ ```js
192
+ const { exportRuntime } = require('@aikdna/kdna-studio-core');
193
+
194
+ const runtimeAsset = exportRuntime.exportRuntimeAsset(project);
195
+ // runtimeAsset.files contains only:
196
+ // - mimetype
197
+ // - kdna.json
198
+ // - payload.kdnab
199
+ // - checksums.json
200
+ ```
201
+
202
+ The exported files are tested against `@aikdna/kdna-core.validate`. In the OPEN
203
+ workspace they are also tested against the current `aikdna/kdna` LoadPlan
204
+ implementation when available.
205
+
206
+ Access values are canonicalized for runtime export:
207
+
208
+ | Studio / legacy value | Runtime value |
209
+ |---|---|
210
+ | `open` | `public` |
211
+ | `protected` | `licensed` |
212
+ | `runtime` | `remote` |
213
+
214
+ Top-level source JSON entries such as `KDNA_Core.json`, `KDNA_Patterns.json`,
215
+ and `KDNA_CARD.json` must not be present in runtime export output.
216
+
160
217
  ## Card Types (v1.0)
161
218
 
162
219
  | Type | Compiles to | Description |
@@ -177,13 +234,16 @@ draft → revised → locked → tested → published → deprecated
177
234
  ```
178
235
 
179
236
  Rules:
180
- - Only `locked`/`tested`/`published` cards can be compiled
181
- - Cards must have Human Lock (`human_lock.by` + `human_lock.statement`) before locking
182
- - Human Lock must confirm `applies_when`, `does_not_apply_when`, `failure_risk` were reviewed
237
+ - `locked`/`tested`/`published` are Studio project review states, not KDNA Core format-validity states.
238
+ - Studio release exports use reviewed cards as release evidence.
239
+ - A validated `.kdna` file can still be structurally valid without Human Lock; trust, authorship, signatures, and release evidence are separate layers.
183
240
 
184
241
  ## Human Lock
185
242
 
186
- AI can propose. Human must confirm. Only locked judgment can compile.
243
+ Human Lock is optional provenance metadata. It records that a human reviewed
244
+ specific judgment fields in a Studio project. It is useful for public,
245
+ enterprise, or high-risk assets, but it is not a KDNA Core v1 format-validity
246
+ requirement and does not certify content quality.
187
247
 
188
248
  ```js
189
249
  lockCard(card, {
@@ -201,7 +261,7 @@ lockCard(card, {
201
261
 
202
262
  Apache-2.0 — see [LICENSE](LICENSE).
203
263
 
204
- KDNA Studio Core is open source. Official KDNA Studio App, hosted collaboration, managed registry, quality review workflows, and enterprise private registry may be commercial services.
264
+ KDNA Studio Core is open source. Official KDNA Studio App, hosted collaboration, managed review workflows, and enterprise private distribution may be commercial services.
205
265
 
206
266
  ## Related
207
267
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-studio-core",
3
- "version": "1.5.3",
4
- "description": "Official KDNA Studio Core SDK for authoring, locking, compiling, and exporting .kdna judgment assets through the KDNA toolchain.",
3
+ "version": "1.5.5",
4
+ "description": "Official KDNA Studio Core SDK for authoring, reviewing, compiling, and exporting .kdna judgment assets through the KDNA toolchain.",
5
5
  "type": "commonjs",
6
6
  "main": "src/index.js",
7
7
  "files": [
@@ -19,12 +19,12 @@
19
19
  "domain-judgment",
20
20
  "authoring",
21
21
  "judgment-cards",
22
- "human-lock",
22
+ "provenance",
23
23
  "compile",
24
24
  "validate"
25
25
  ],
26
26
  "dependencies": {
27
- "@aikdna/kdna-core": "^0.11.1",
27
+ "@aikdna/kdna-core": "^0.12.0",
28
28
  "cbor-x": "^1.6.4"
29
29
  },
30
30
  "engines": {
@@ -36,6 +36,6 @@
36
36
  "test:all": "npm run lint && npm test"
37
37
  },
38
38
  "devDependencies": {
39
- "@aikdna/kdna-cli": "^0.25.0"
39
+ "@aikdna/kdna-cli": "^0.26.4"
40
40
  }
41
41
  }
@@ -281,6 +281,13 @@ function compileManifest(project, files, identity = null) {
281
281
  authoring_tool_version: version,
282
282
  compiler: '@aikdna/kdna-studio-core',
283
283
  compiler_version: version,
284
+ conformance: {
285
+ passed: true,
286
+ spec_version: '2.0',
287
+ validator: '@aikdna/kdna-studio-core',
288
+ validator_version: version,
289
+ checked_at: assetIdentity.compiled_at,
290
+ },
284
291
  source_mode: project.source_mode || 'blank',
285
292
  asset_uid: assetIdentity.asset_uid,
286
293
  project_uid: assetIdentity.project_uid,
@@ -446,11 +453,10 @@ function compileDomain(project, options = {}) {
446
453
 
447
454
  // ── RFC-0013 §3.1/§3.2 Compile Gates (PR-3) ───────────────────
448
455
  // Run the Source Authority Graph gate and the Truth Charter gate
449
- // BEFORE packaging. PR-2: strictAuthority now defaults to true so
450
- // missing/unstable SAG/TC are surfaced as gate errors that block
451
- // compilation. Pass options.strictAuthority = false to opt out
452
- // (legacy workspaces only).
453
- const strictAuthority = options.strictAuthority !== false;
456
+ // BEFORE packaging. By default, missing/unstable SAG/TC are warnings.
457
+ // Pass options.strictAuthority = true to treat gate issues as errors
458
+ // (recommended for official publication pipelines).
459
+ const strictAuthority = options.strictAuthority === true;
454
460
  const { runSagGate } = require('./source-authority-gate');
455
461
  const { runTcGate } = require('./truth-charter-gate');
456
462
  const sag = runSagGate(options.sourceAuthority, { strict: strictAuthority });
@@ -0,0 +1,220 @@
1
+ const crypto = require('crypto');
2
+ const { compileDomain } = require('../compile');
3
+
4
+ const MIMETYPE_V1 = 'application/vnd.kdna.asset';
5
+
6
+ function json(value) {
7
+ return `${JSON.stringify(value, null, 2)}\n`;
8
+ }
9
+
10
+ function domainIdFromName(name = 'domain') {
11
+ const base = String(name).includes('/') ? String(name).split('/').pop() : String(name);
12
+ const normalized = base
13
+ .toLowerCase()
14
+ .replace(/[^a-z0-9_]+/g, '_')
15
+ .replace(/^_+|_+$/g, '');
16
+ return /^[a-z]/.test(normalized) ? normalized : `domain_${normalized || 'untitled'}`;
17
+ }
18
+
19
+ function canonicalAccess(value) {
20
+ if (!value || value === 'open') return 'public';
21
+ if (value === 'protected') return 'licensed';
22
+ if (value === 'runtime') return 'remote';
23
+ return value;
24
+ }
25
+
26
+ function semverValue(value, fallback = '0.1.0') {
27
+ const raw = String(value || '').trim();
28
+ if (/^[0-9]+\.[0-9]+\.[0-9]+([+-].+)?$/.test(raw)) return raw;
29
+ const twoPart = raw.match(/^([0-9]+)\.([0-9]+)$/);
30
+ if (twoPart) return `${twoPart[1]}.${twoPart[2]}.0`;
31
+ return fallback;
32
+ }
33
+
34
+ function canonicalLineage(lineage) {
35
+ if (!lineage || typeof lineage !== 'object') return { type: 'original' };
36
+ const allowed = new Set([
37
+ 'original',
38
+ 'fork',
39
+ 'adaptation',
40
+ 'translation',
41
+ 'private_variant',
42
+ 'organization_variant',
43
+ 'course_variant',
44
+ ]);
45
+ if (allowed.has(lineage.type)) return lineage;
46
+ return {
47
+ ...lineage,
48
+ type: 'adaptation',
49
+ source_lineage_type: lineage.type || 'unknown',
50
+ };
51
+ }
52
+
53
+ function sha256Hex(value) {
54
+ return crypto.createHash('sha256').update(Buffer.isBuffer(value) ? value : Buffer.from(value)).digest('hex');
55
+ }
56
+
57
+ function buildChecksums(files) {
58
+ const entries = {
59
+ 'kdna.json': { algorithm: 'sha256', value: sha256Hex(files['kdna.json']) },
60
+ 'payload.kdnab': { algorithm: 'sha256', value: sha256Hex(files['payload.kdnab']) },
61
+ };
62
+ const combined = Object.keys(entries)
63
+ .sort()
64
+ .map((name) => `${name}:${entries[name].value}`)
65
+ .join('\n');
66
+ return {
67
+ algorithm: 'sha256',
68
+ manifest_digest: `sha256:${entries['kdna.json'].value}`,
69
+ payload_digest: `sha256:${entries['payload.kdnab'].value}`,
70
+ asset_digest: `sha256:${sha256Hex(combined)}`,
71
+ entries,
72
+ };
73
+ }
74
+
75
+ function parseJsonFile(files, name, fallback = null) {
76
+ if (!files[name]) return fallback;
77
+ return JSON.parse(files[name]);
78
+ }
79
+
80
+ function buildPayload(compiled) {
81
+ const core = parseJsonFile(compiled.files, 'KDNA_Core.json', {});
82
+ const patterns = parseJsonFile(compiled.files, 'KDNA_Patterns.json', {});
83
+ const scenarios = parseJsonFile(compiled.files, 'KDNA_Scenarios.json', { scenes: [] });
84
+ const cases = parseJsonFile(compiled.files, 'KDNA_Cases.json', { cases: [] });
85
+ const reasoning = parseJsonFile(compiled.files, 'KDNA_Reasoning.json', { reasoning_chains: [] });
86
+ const evolution = parseJsonFile(compiled.files, 'KDNA_Evolution.json', { changelog: [], version_notes: [] });
87
+
88
+ const firstAxiom = Array.isArray(core.axioms) ? core.axioms[0] : null;
89
+ return {
90
+ profile: 'judgment-profile-v1',
91
+ core: {
92
+ highest_question:
93
+ core.meta?.load_condition ||
94
+ firstAxiom?.one_sentence ||
95
+ `What judgment should be loaded for ${core.meta?.domain || 'this domain'}?`,
96
+ axioms: Array.isArray(core.axioms) ? core.axioms : [],
97
+ boundaries: Array.isArray(core.boundaries) ? core.boundaries : [],
98
+ risk_model: {
99
+ risks: Array.isArray(core.risks) ? core.risks : [],
100
+ },
101
+ },
102
+ patterns: Array.isArray(patterns.misunderstandings) ? patterns.misunderstandings : [],
103
+ scenarios: Array.isArray(scenarios.scenes) ? scenarios.scenes : [],
104
+ cases: Array.isArray(cases.cases) ? cases.cases : [],
105
+ reasoning: {
106
+ self_checks: Array.isArray(patterns.self_check) ? patterns.self_check : [],
107
+ failure_modes: Array.isArray(reasoning.reasoning_chains) ? reasoning.reasoning_chains : [],
108
+ },
109
+ evolution: {
110
+ stages: Array.isArray(evolution.stages) ? evolution.stages : [],
111
+ evolution_layers: Array.isArray(evolution.evolution_layers) ? evolution.evolution_layers : [],
112
+ measurement: Array.isArray(evolution.measurement) ? evolution.measurement : [],
113
+ changelog: Array.isArray(evolution.changelog) ? evolution.changelog : [],
114
+ version_notes: Array.isArray(evolution.version_notes) ? evolution.version_notes : [],
115
+ },
116
+ };
117
+ }
118
+
119
+ function buildManifest(project, compiled, payloadBytes, options = {}) {
120
+ const sourceManifest = parseJsonFile(compiled.files, 'kdna.json', {});
121
+ const packageVersion = require('../../package.json').version;
122
+ const access = canonicalAccess(options.access || project.release?.access || sourceManifest.access);
123
+ const domainId = sourceManifest.domain_id || domainIdFromName(project.name);
124
+ const now = options.timestamp || sourceManifest.updated_at || sourceManifest.updated || new Date().toISOString();
125
+ const creator = project.author || sourceManifest.creator || sourceManifest.author || { name: 'Unknown' };
126
+
127
+ const manifest = {
128
+ kdna_version: '1.0',
129
+ asset_id: options.asset_id || `kdna:studio:${domainId}`,
130
+ asset_uid: options.asset_uid || `urn:uuid:${sourceManifest.asset_uid || compiled.identity?.asset_uid}`,
131
+ asset_type: 'domain',
132
+ title: options.title || project.title || project.name,
133
+ version: semverValue(sourceManifest.version || project.release?.version, '0.1.0'),
134
+ judgment_version: semverValue(sourceManifest.judgment_version || project.release?.judgment_version || project.release?.version, '0.1.0'),
135
+ created_at: options.created_at || sourceManifest.created_at || new Date(project.created || now).toISOString(),
136
+ updated_at: options.updated_at || now,
137
+ creator: {
138
+ name: creator.name || creator.display_name || 'Unknown',
139
+ id: creator.id || creator.creator_id || undefined,
140
+ },
141
+ compatibility: {
142
+ min_loader_version: '1.0.0',
143
+ profile: 'judgment-profile-v1',
144
+ },
145
+ payload: {
146
+ path: 'payload.kdnab',
147
+ encoding: 'json',
148
+ encrypted: false,
149
+ digest: `sha256:${sha256Hex(payloadBytes)}`,
150
+ },
151
+ access,
152
+ summary: sourceManifest.description || project.release?.description || project.name,
153
+ language: project.default_language || sourceManifest.default_language || 'en',
154
+ languages: project.languages || sourceManifest.languages || ['en'],
155
+ license: project.license || sourceManifest.license || { type: 'CC-BY-4.0' },
156
+ keywords: sourceManifest.keywords || [],
157
+ lineage: canonicalLineage(project.lineage || sourceManifest.lineage),
158
+ load_contract: {
159
+ default_profile: 'compact',
160
+ profiles: {
161
+ index: { requires_decryption: false, max_tokens_hint: 200 },
162
+ compact: { requires_decryption: false, max_tokens_hint: 500 },
163
+ scenario: { requires_decryption: false, selection: 'triggered_sections_only' },
164
+ full: { requires_decryption: false, intended_for: ['audit', 'reference'] },
165
+ },
166
+ },
167
+ authoring: {
168
+ compiler: '@aikdna/kdna-studio-core',
169
+ compiler_version: packageVersion,
170
+ conformance: {
171
+ passed: true,
172
+ spec_version: '1.0',
173
+ validator: '@aikdna/kdna-studio-core/export-runtime',
174
+ validator_version: packageVersion,
175
+ checked_at: now,
176
+ },
177
+ source_build_id: compiled.identity?.build_id || sourceManifest.build_id || null,
178
+ studio_project_digest: sourceManifest.authoring?.studio_project_digest || null,
179
+ human_lock_required: true,
180
+ human_lock_count: sourceManifest.authoring?.human_lock_count || compiled.stats?.locked_cards || 0,
181
+ },
182
+ };
183
+
184
+ if (access === 'licensed') {
185
+ manifest.entitlement = options.entitlement || { profile: 'local_receipt', offline: true, revocable: true };
186
+ }
187
+ if (access === 'remote') {
188
+ manifest.runtime = options.runtime || { endpoint: null };
189
+ }
190
+ return manifest;
191
+ }
192
+
193
+ function exportRuntimeAsset(project, options = {}) {
194
+ const compiled = options.compiled || compileDomain(project, options.compile || {});
195
+ const payload = buildPayload(compiled);
196
+ const payloadBytes = json(payload);
197
+ const manifest = buildManifest(project, compiled, payloadBytes, options);
198
+ const files = {
199
+ mimetype: MIMETYPE_V1,
200
+ 'kdna.json': json(manifest),
201
+ 'payload.kdnab': payloadBytes,
202
+ };
203
+ files['checksums.json'] = json(buildChecksums(files));
204
+ return {
205
+ files,
206
+ manifest,
207
+ payload,
208
+ source: compiled,
209
+ };
210
+ }
211
+
212
+ module.exports = {
213
+ MIMETYPE_V1,
214
+ exportRuntimeAsset,
215
+ buildPayload,
216
+ buildManifest,
217
+ buildChecksums,
218
+ canonicalAccess,
219
+ canonicalLineage,
220
+ };
package/src/index.js CHANGED
@@ -21,6 +21,7 @@ const cards = require('./cards');
21
21
  const compile = require('./compile');
22
22
  const creatorIdentity = require('./creator-identity');
23
23
  const evidence = require('./evidence');
24
+ const exportRuntime = require('./export-runtime');
24
25
  const governance = require('./governance');
25
26
  const i18n = require('./i18n');
26
27
  const packaging = require('./packaging');
@@ -45,6 +46,7 @@ module.exports = {
45
46
  provenance,
46
47
  pipeline,
47
48
  governance,
49
+ exportRuntime,
48
50
  i18n,
49
51
  creator: creatorIdentity,
50
52
  distillation,
@@ -2,7 +2,7 @@
2
2
  * Runtime CLI adapter for dev-source diagnostics and asset verification.
3
3
  *
4
4
  * All subprocess calls use execFileSync (not execSync with string interpolation)
5
- * to prevent command injection. Trusted compile/export is implemented by
5
+ * to prevent command injection. Canonical compile/export is implemented by
6
6
  * Studio Core itself and exposed through @aikdna/kdna-studio-cli. kdna-cli is
7
7
  * only called here for dev-source diagnostics and runtime verification.
8
8
  */
@@ -244,7 +244,7 @@ function checkHumanLockGate(project) {
244
244
  issues.push({
245
245
  cardId,
246
246
  type: card.type,
247
- reason: `judgment-class card "${cardId}" (${card.type}) is not locked. Human Lock required before export.`
247
+ reason: `judgment-class card "${cardId}" (${card.type}) is not approved for Studio export. Review/provenance approval is required by this Studio workflow.`
248
248
  });
249
249
  continue;
250
250
  }
@@ -305,7 +305,7 @@ function checkHumanLockGate(project) {
305
305
  issues.push({
306
306
  cardId: '(project)',
307
307
  type: 'project',
308
- reason: 'No judgment-class cards are locked. At least one axiom, boundary, or risk card must be Human Locked before export.'
308
+ reason: 'No judgment-class cards are approved. At least one axiom, boundary, or risk card must be reviewed before Studio export.'
309
309
  });
310
310
  }
311
311
 
@@ -46,11 +46,14 @@ function computeReadiness(project) {
46
46
  }
47
47
 
48
48
  // ── I18N check (v1.2.0) ─────────────────────────────────────────
49
- const isOfficial = project.name?.startsWith('@aikdna/') || project.release?.official === true;
49
+ // I18N gates are triggered by declared languages, not by scope prefix.
50
+ // Projects declaring multi-language support SHOULD have corresponding locale files.
50
51
  const i18nCoverage = computeI18nCoverage(project);
51
- if (isOfficial && i18nCoverage.level === 'L0') {
52
- blocking.push('I18N: official domains require at least L1 (KDNA_CARD.json + README in locales/zh-CN/)');
53
- } else if (isOfficial && i18nCoverage.level === 'L1') {
52
+ const declaredLanguages = (project.languages || []).filter(l => l !== project.default_language);
53
+ const hasMultiLangIntent = declaredLanguages.length > 0 || (project.i18n_level && project.i18n_level !== 'L0');
54
+ if (hasMultiLangIntent && i18nCoverage.level === 'L0') {
55
+ warnings.push('I18N: project declares multi-language intent but has no locale files (L0). Add at least L1 (KDNA_CARD.json + README in locales/).');
56
+ } else if (hasMultiLangIntent && i18nCoverage.level === 'L1') {
54
57
  warnings.push('I18N: L1 achieved (card + readme). Recommended: L2 overlay for publishable grade.');
55
58
  }
56
59
  for (const issue of govResult.issues) {
@@ -167,7 +170,7 @@ function buildResult(grade, blocking, warnings, project, detail = {}) {
167
170
  next_step: grade === 'draft_grade' ? 'Lock at least 3 axioms with boundaries and 50% Feynman.' :
168
171
  grade === 'human_controlled' ? 'Add 5+ rated evals and 3+ self-checks.' :
169
172
  grade === 'tested_grade' ? 'Add 10+ evals, complete Feynman on all axioms/misunderstandings, resolve all blocking issues.' :
170
- 'Ready for Studio compile/export. Publish the resulting .kdna with kdna publish <file.kdna>.',
173
+ 'Ready for Studio compile/export. Validate the resulting .kdna with kdna validate, plan with kdna plan-load, then load only when loadable.',
171
174
  };
172
175
  }
173
176