@aikdna/kdna-core 0.36.0 → 0.37.1-rc.browser.1

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 (64) hide show
  1. package/README.md +12 -2
  2. package/package.json +11 -1
  3. package/schema/manifest.schema.json +2 -1
  4. package/src/public-contract/browser-native/generated-contract.json +3 -3
  5. package/src/public-contract/browser-native/sections/contract.json +2 -2
  6. package/src/public-contract/browser-protected/request.js +77 -0
  7. package/src/public-contract/browser-protected/state.js +200 -0
  8. package/src/public-contract/browserwhole06/contract.json +2 -2
  9. package/src/public-contract/creation06/contract.json +2 -2
  10. package/src/public-contract/creation06/generation-manifest.json +9 -9
  11. package/src/public-contract/execution06/contract.json +2 -2
  12. package/src/public-contract/execution06/generation-manifest.json +9 -9
  13. package/src/public-contract/generated-contract.json +3 -3
  14. package/src/public-contract/issuer-contract.generated.json +6 -6
  15. package/src/public-contract/issuer-validators.generated.js +7 -7
  16. package/src/public-contract/key-grant-issuer-node.d.ts +1 -1
  17. package/src/public-contract/package-set-contract.generated.json +5 -5
  18. package/src/public-contract/package-set-node.d.ts +1 -1
  19. package/src/public-contract/package-set-validators.generated.js +9 -9
  20. package/src/public-contract/packageset06/contract.json +2 -2
  21. package/src/public-contract/packageset06/generation-manifest.json +9 -9
  22. package/src/public-contract/protected-browser-contract/contract.json +11824 -0
  23. package/src/public-contract/protected-browser-contract/descriptor.json +5 -0
  24. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedAdmissionResult.json +443 -0
  25. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedAuthorityContext.json +939 -0
  26. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedBinding.json +156 -0
  27. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedCallResult.json +10489 -0
  28. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedDeliveryToken.json +10 -0
  29. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedExpansionHandle.json +320 -0
  30. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedHostContext.json +677 -0
  31. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedHostObservation.json +208 -0
  32. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedReadAuthority.json +10 -0
  33. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedReadResult.json +10795 -0
  34. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedRequest.json +539 -0
  35. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedRequestAdmission.json +1016 -0
  36. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedSignaturePolicy.json +35 -0
  37. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedSnapshotData.json +8451 -0
  38. package/src/public-contract/protected-browser-contract/schemas/BrowserProtectedTransportCommitResult.json +304 -0
  39. package/src/public-contract/protected-browser-contract/schemas/TrustedBrowserProtectedHost.json +10 -0
  40. package/src/public-contract/protected-browser-contract/types.d.ts +389 -0
  41. package/src/public-contract/protected-browser-contract/validators.cjs +223756 -0
  42. package/src/public-contract/protected-browser.d.ts +17 -0
  43. package/src/public-contract/protected-browser.js +4 -0
  44. package/src/public-contract/protected-browser.mjs +2 -0
  45. package/src/public-contract/protected-sections-browser.d.ts +11 -0
  46. package/src/public-contract/protected-sections-browser.js +22 -0
  47. package/src/public-contract/protected-sections-browser.mjs +2 -0
  48. package/src/public-contract/protected-source-contract.generated.json +8 -8
  49. package/src/public-contract/protected-source-node.d.ts +1 -1
  50. package/src/public-contract/protection-admission-browser.js +132 -0
  51. package/src/public-contract/protection-contract.generated.json +14 -13
  52. package/src/public-contract/protection-crypto.js +7 -17
  53. package/src/public-contract/protection-envelope-codec.js +76 -13
  54. package/src/public-contract/protection-node.d.ts +2 -2
  55. package/src/public-contract/protection-validators.generated.js +5 -5
  56. package/src/public-contract/retained/contract.json +2 -2
  57. package/src/public-contract/retained/generation-manifest.json +9 -9
  58. package/src/public-contract/retained-browser06/contract.json +2 -2
  59. package/src/public-contract/sectionbytes/contract.json +2 -2
  60. package/src/public-contract/sectionbytes/generation-manifest.json +9 -9
  61. package/src/public-contract/sections/contract.json +2 -2
  62. package/src/public-contract/sections/generation-manifest.json +9 -9
  63. package/src/public-contract/source-validators.generated.js +6 -6
  64. package/src/public-contract/source06/contract.json +2 -2
package/README.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # KDNA Core — R2 candidate
2
2
 
3
- Unpublished `R2` source candidate: actual source package `0.36.0`, Core `kdna.core/0.8.2`, Container `0.5.0`, Payload `0.5.1`, Canonical IR `0.6.1`, with native Capsule/Plan/Host/Trace `0.3.1`. The published incumbent is `0.22.0`; this source candidate is not a published replacement. See the [specification index](../../SPEC-INDEX.md), the [execution contract](../../specs/execution-contract-0.3.md) and the [PackageSet node surface](../../specs/package-set-node.md). Implementation, independent byte-bound acceptance, installed consumer rebinding and publication are separate.
3
+ Source candidate (unreleased): actual source package `0.37.1-rc.browser.1`, Core `kdna.core/0.8.2`, Container `0.5.0`, Payload `0.5.1`, Canonical IR `0.6.1`, with native Capsule/Plan/Host/Trace `0.3.1`. See the [specification index](../../SPEC-INDEX.md), the [execution contract](../../specs/execution-contract-0.3.md) and the [PackageSet node surface](../../specs/package-set-node.md). Implementation, independent byte-bound acceptance, installed consumer rebinding and publication are separate.
4
+
5
+ Published and source coordinates are separate: `npm i @aikdna/kdna-core` resolves to the published stable `0.37.0`, while this source is the candidate `0.37.1-rc.browser.1`, addressed by its exact version or the `browser-preview` dist-tag and never carrying `latest`.
6
+
7
+ The published stable release remains Core `0.37.0`, paired with Read `0.11.1`; its artifacts and release evidence remain separate from this candidate. Core `0.37.0` supersedes the `0.36.0` incumbent.
4
8
 
5
9
  This source description follows [`package.json`](package.json).
6
- Read source `0.11.0` declares this exact Core peer. Runtime CLI
10
+ Read source `0.11.2-rc.browser.1` declares this exact Core peer. Runtime CLI
7
11
  0.40 and MCP 0.8.1 retain their separate Core 0.34 / Read 0.9 archives; see the
8
12
  [matching-delivery guide](../../docs/core-read-current-status.md#choose-and-obtain-one-matching-delivery).
9
13
  Editing this source README does not replace a previously fixed archive or
@@ -25,6 +29,12 @@ Core admits one immutable container, validates its Manifest and typed Payload, r
25
29
  | `/remote-runtime` | `loadRemoteRuntimeAsset` | Preserved explicit legacy 0.1 remote loader; independently declared types, no R2 conversion |
26
30
  | `/read-boundary` | `inspectSnapshot`, `isProtectedSnapshot` | Pure private-snapshot probes; availability is not current authority |
27
31
  | `/protection-node` | `getProtectionContract`, `admitProtectedNode`, `bindProtectionOperation`, `disposeProtectionOperation`, `protectSourceBytes` | Explicit Node protection, trusted provider and opaque operation |
32
+ | `/protected-browser` | `getProtectionContract`, `admitProtectedBrowser` | Host-supplied container bytes, plaintext Payload and unlock observation; trusted provider |
33
+ | `/protected-sections-browser` | `admitProtectedPayloadRequestJson`, `inspectProtectedPayloadRequest`, `createProtectedPayloadReadAuthorityJson`, `admitProtectedSectionBrowser`, `inspectProtectedPayloadSnapshot`, `bindProtectedPayloadRequest`, `disposeProtectedSectionOperation` | Genuine browser admission snapshot, closed JSON request and independently trusted authority |
34
+
35
+ The candidate `/protected-sections-browser` entry retains one genuine accepted snapshot from `/protected-browser`'s `admitProtectedBrowser`. Admit the request JSON, create an independently trusted Read authority, then call `admitProtectedSectionBrowser(snapshot, request, authority)` and retain its returned operation and normalized request. Bind later request JSON with `bindProtectedPayloadRequest`; close the operation with `disposeProtectedSectionOperation`. The [generated declarations](src/public-contract/protected-sections-browser.d.ts) define the seven callables and closed inputs.
36
+
37
+ The original input triple is container bytes, Host-supplied plaintext Payload and an unlock observation. It does not prove decryption or ciphertext/plaintext authentication. This adapter performs no new decryption or physical read; its observation and receipt preserve `host_supplied_triple` and `observation_not_authority`. It uses the independent base tuple above, including container `0.5.0` and Read `kdna.read/0.6.4`; Node native-section witnesses and serialized snapshot copies cannot establish browser origin. Disclosure additionally requires the [Read browser adapter](../kdna-read/README.md#protected-browser-read-candidate) and its independently trusted Host scope.
28
38
 
29
39
  ```js
30
40
  import { admitNode } from '@aikdna/kdna-core/node';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-core",
3
- "version": "0.36.0",
3
+ "version": "0.37.1-rc.browser.1",
4
4
  "description": "Public KDNA Core with bounded component interpretation and Canonical IR.",
5
5
  "engines": {
6
6
  "node": ">=20"
@@ -60,6 +60,11 @@
60
60
  "import": "./src/public-contract/protection-node.mjs",
61
61
  "require": "./src/public-contract/protection-node.js"
62
62
  },
63
+ "./protected-browser": {
64
+ "types": "./src/public-contract/protected-browser.d.ts",
65
+ "import": "./src/public-contract/protected-browser.mjs",
66
+ "require": "./src/public-contract/protected-browser.js"
67
+ },
63
68
  "./protected-source-node": {
64
69
  "types": "./src/public-contract/protected-source-node.d.ts",
65
70
  "import": "./src/public-contract/protected-source-node.mjs",
@@ -124,6 +129,11 @@
124
129
  "types": "./src/public-contract/retained-sections-browser.d.ts",
125
130
  "import": "./src/public-contract/retained-sections-browser.mjs",
126
131
  "require": "./src/public-contract/retained-sections-browser.js"
132
+ },
133
+ "./protected-sections-browser": {
134
+ "types": "./src/public-contract/protected-sections-browser.d.ts",
135
+ "import": "./src/public-contract/protected-sections-browser.mjs",
136
+ "require": "./src/public-contract/protected-sections-browser.js"
127
137
  }
128
138
  },
129
139
  "types": "src/public-contract/types.d.ts",
@@ -281,7 +281,8 @@
281
281
  "kdna.encryption.licensed-entry",
282
282
  "kdna.encryption.password",
283
283
  "kdna.encryption.password.scrypt",
284
- "kdna.envelope.external-grant"
284
+ "kdna.envelope.external-grant",
285
+ "kdna.envelope.aead"
285
286
  ]
286
287
  },
287
288
  "profile_version": {
@@ -809,12 +809,12 @@
809
809
  },
810
810
  "schema_paths": {
811
811
  "CanonicalIR": "specs/canonical-ir-0.6.1.schema.json",
812
- "IssuerResultObservation": "specs/external-grant-issuer-r2-binding-7.schema.json",
812
+ "IssuerResultObservation": "specs/external-grant-issuer-r2-binding-8.schema.json",
813
813
  "Manifest": "schema/manifest-container-0.5.0-judgment-0.5.1.schema.json",
814
814
  "PackageSetNodeSurface": "specs/package-set-node-0.2.1.schema.json",
815
815
  "Payload": "schema/payload-profile-0.5.1.schema.json",
816
- "ProtectedSourceObservation": "specs/protected-source-r2-binding-7.schema.json",
817
- "ProtectionDefinitionObservation": "specs/protection-admission-r2-binding-7.schema.json",
816
+ "ProtectedSourceObservation": "specs/protected-source-r2-binding-8.schema.json",
817
+ "ProtectionDefinitionObservation": "specs/protection-admission-r2-binding-8.schema.json",
818
818
  "PublicAgentHostReceipt": "schema/agent-host-receipt-0.3.1.schema.json",
819
819
  "PublicAgentHostRequest": "schema/agent-host-request-0.3.1.schema.json",
820
820
  "PublicConsumptionPlan": "schema/consumption-plan-0.3.1.schema.json",
@@ -2,8 +2,8 @@
2
2
  "candidate_only": true,
3
3
  "source": {
4
4
  "path": "specs/public-semantic-source.json",
5
- "bytes": 1435348,
6
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
5
+ "bytes": 1506884,
6
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
7
7
  },
8
8
  "historical_original_source": {
9
9
  "scope": "historical_original_contract_source_identity_not_current_generator_input",
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+ const S = require('./state.js'), { C } = S;
3
+ const fixed = n => String(n).padStart(16, '0');
4
+ const count = value => new TextEncoder().encode(C.strict.canonicalJson(value)).length;
5
+ const correlation = id => C.strict.identifier(id) ? {
6
+ state: 'validated', request_id: id
7
+ } : {
8
+ state: 'unavailable', request_id: null
9
+ };
10
+ function failure(candidate) {
11
+ const id = Object.getOwnPropertyDescriptor(candidate ?? {}, 'request_id')?.value, body = {
12
+ contract: 'kdna.read-admission/0.1.0', code: 'READ_INPUT_INVALID', diagnostic: {
13
+ stage: 'admission', severity: 'error', reason: 'mode_shape_invalid', field: '$candidate'
14
+ }, correlation: correlation(id), control_budget: {
15
+ limit_bytes: 4096, actual_bytes: '0000000000000000'
16
+ }
17
+ };
18
+ body.control_budget.actual_bytes = fixed(count(body));
19
+ const out = {
20
+ channel: 'admission_rejection', envelope: null, admission_rejection: body, control: null, transport_failure: null
21
+ };
22
+ C.validate('BrowserProtectedRequestAdmission', out);
23
+ return S.frozen(out);
24
+ }
25
+ function versionRejection(candidate, code) {
26
+ const envelope = {
27
+ contract: 'kdna.protected-browser-read/0.1.0-candidate', request_id: candidate.request_id, status: 'rejected', tuple: null, asset: null, snapshot_id: null, digests: null, content: null, states: {
28
+ core: 'not_evaluated', interpretation: 'not_evaluated', writer: 'not_evaluated', confirmation: 'not_evaluated', read_permission: 'not_evaluated', action_authorization: 'not_evaluated'
29
+ }, diagnostics: [{
30
+ code, stage: 'version', severity: 'error', subject: null, field: null
31
+ }], omissions: [], assessment: {
32
+ state: 'not_evaluated', kind: null, assessor_id: null, evidence_ref: null
33
+ }, receipt: {
34
+ receipt_id: 'receipt:' + candidate.request_id, request_id: candidate.request_id, snapshot_id: null, host_id: null, host_epoch: null, decision_id: null, disclosed_at: null, delivery: 'not_delivered'
35
+ }, budget: {
36
+ limit_bytes: candidate.budget_bytes, required_bytes: '0000000000000000', actual_bytes: '0000000000000000'
37
+ }
38
+ };
39
+ const size = count(envelope);
40
+ envelope.budget.actual_bytes = fixed(size);
41
+ envelope.budget.required_bytes = fixed(size);
42
+ const out = size <= candidate.budget_bytes ? {
43
+ channel: 'read_envelope', envelope, admission_rejection: null, control: null, transport_failure: null
44
+ } : {
45
+ channel: 'no_body_control', envelope: null, admission_rejection: null, control: {
46
+ code: 'READ_RESPONSE_BUDGET_TOO_SMALL', semantic_cause: code, correlation: correlation(candidate.request_id), body_bytes: 0
47
+ }, transport_failure: null
48
+ };
49
+ C.validate('BrowserProtectedRequestAdmission', out);
50
+ return S.frozen(out);
51
+ }
52
+ function admit(candidateJson) {
53
+ let candidate;
54
+ try {
55
+ candidate = C.parseJsonText(candidateJson);
56
+ const data = candidate;
57
+ C.keys(data, ['request_id', 'tuple', 'budget_bytes', 'mode', 'selection', 'handle']);
58
+ C.need(C.strict.identifier(data.request_id) && C.strict.uint(data.budget_bytes), 'READ_INPUT_INVALID');
59
+ const t = data.tuple;
60
+ C.need(t && typeof t === 'object' && !Array.isArray(t) && Object.keys(t).every(k => Object.hasOwn(S.tuple, k) && typeof t[k] === 'string'), 'READ_INPUT_INVALID');
61
+ if (Object.keys(t).length !== Object.keys(S.tuple).length || Object.entries(S.tuple).some(([k, v]) => t[k] !== v)) {
62
+ const baseline = require('../generated-contract.json'), old = [baseline.versionTuple, ...baseline.types.UnsupportedVersionTuple.anyOf.map(x => Object.fromEntries(Object.entries(x.properties).map(([k, v]) => [k, v.const])))];
63
+ const historical = old.some(value => Object.keys(t).length === Object.keys(value).length && Object.entries(value).every(([k, v]) => t[k] === v));
64
+ return versionRejection(data, historical ? 'READ_UNSUPPORTED_VERSION' : Object.keys(S.tuple).some(k => k !== 'payload_profile' && t[k] === S.tuple[k]) ? 'READ_MIXED_VERSION_TUPLE' : 'READ_UNSUPPORTED_VERSION');
65
+ }
66
+ C.validate('BrowserProtectedRequest', data);
67
+ return Object.freeze({
68
+ channel: 'admitted_request', request: S.mintRequest(data)
69
+ });
70
+ }
71
+ catch (e) {
72
+ return failure(candidate);
73
+ }
74
+ }
75
+ module.exports = {
76
+ admit, failure
77
+ };
@@ -0,0 +1,200 @@
1
+ 'use strict';
2
+ const strict = require('../browser-native/strict-input.js');
3
+ const { digestCanonical } = require('../digests.js');
4
+ const { inspectSnapshot, markProtectedSnapshot } = require('../brand.js');
5
+ const contract = require('../protected-browser-contract/contract.json');
6
+ const validators = require('../protected-browser-contract/validators.cjs');
7
+ const origins = new WeakMap(), requests = new WeakMap(), authorities = new WeakMap();
8
+ const operations = new WeakMap(), snapshots = new WeakMap(), checkpoints = new WeakMap(), failures = new WeakMap();
9
+ const tuple = require('../generated-contract.json').versionTuple;
10
+ const frozen = strict.freeze;
11
+ function need(ok, code = 'READ_INPUT_INVALID') {
12
+ if (!ok) { const error = new Error(code); failures.set(error, code); throw error; }
13
+ }
14
+ function validate(name, value) {
15
+ strict.assertStrictJson(value);
16
+ need(typeof validators[name] === 'function' && validators[name](value), 'READ_INPUT_INVALID');
17
+ scalars(value, contract.types[name]);
18
+ return value;
19
+ }
20
+ function scalars(value, shape, depth = 0) {
21
+ need(depth <= 64);
22
+ if (shape.$ref) {
23
+ const name = shape.$ref.slice(8);
24
+ if (name === 'Identifier') need(strict.identifier(value));
25
+ if (['EntryName', 'RuntimeMandatoryEntryName'].includes(name)) need(strict.entryName(value));
26
+ if (name === 'Timestamp') need(strict.validTimestamp(value));
27
+ return scalars(value, contract.types[name], depth);
28
+ }
29
+ if (typeof value === 'string') need(strict.scalarString(value));
30
+ if (value && typeof value === 'object') {
31
+ for (const [key, child] of Object.entries(shape.properties ?? {}))
32
+ if (Object.hasOwn(value, key)) scalars(value[key], child, depth + 1);
33
+ if (Array.isArray(value) && shape.items) for (const child of value) scalars(child, shape.items, depth + 1);
34
+ }
35
+ for (const child of shape.allOf ?? []) scalars(value, child, depth);
36
+ for (const child of shape.oneOf ?? shape.anyOf ?? []) {
37
+ const branch = child.$ref ? contract.types[child.$ref.slice(8)] : child;
38
+ if (branch.type && (branch.type === 'null' ? value !== null : branch.type === 'array' ? !Array.isArray(value) : typeof value !== branch.type)) continue;
39
+ if (Object.entries(branch.properties ?? {}).some(([key, field]) => Object.hasOwn(field, 'const') && Object.hasOwn(value ?? {}, key) && value[key] !== field.const)) continue;
40
+ scalars(value, child, depth);
41
+ }
42
+ }
43
+ function parseJsonText(value) { need(typeof value === 'string'); return strict.parseJson(value); }
44
+ function keys(value, names) {
45
+ need(value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === names.length && names.every(k => Object.hasOwn(value, k)));
46
+ }
47
+ const C = { strict, contract, validate, keys, need, parseJsonText, isFailure: e => failures.has(e), failureCode: e => failures.get(e) ?? null };
48
+ function failed(code = 'PROTECTION_OPERATION_UNTRUSTED', stage = 'input') {
49
+ return frozen({ status: 'protection_failed', diagnostic: { code, stage }, checked_at_ms: null });
50
+ }
51
+ // Registration is private to successful browser admission. Public snapshot fields,
52
+ // JSON copies and Node admissions cannot establish this provenance.
53
+ function register(snapshot, metadata) {
54
+ const view = inspectSnapshot(snapshot);
55
+ need(view && strict.canonicalJson(view.tuple) === strict.canonicalJson(tuple), 'READ_SNAPSHOT_UNATTESTED');
56
+ const origin = { phase: 'available', view, metadata: frozen(metadata) };
57
+ origins.set(snapshot, origin);
58
+ markProtectedSnapshot(snapshot, () => origin.phase !== 'closed');
59
+ }
60
+ function mintRequest(data, sourceDigest = null) {
61
+ const token = Object.freeze({}), copy = frozen(strict.copyJson(data)), digest = digestCanonical(copy);
62
+ requests.set(token, { data: copy, digest, sourceDigest: sourceDigest ?? digest, operation: null });
63
+ return token;
64
+ }
65
+ function request(token) { const r = requests.get(token); return r && (!r.operation || operation(r.operation)) ? r : null; }
66
+ function inspectRequest(token) { return request(token)?.data ?? null; }
67
+ function normalized(record, view) {
68
+ if (record.data.mode !== 'exact_selection') return mintRequest(record.data, record.sourceDigest);
69
+ const s = record.data.selection;
70
+ need(s.asset_id === view.asset.asset_id, 'READ_ASSET_MISMATCH');
71
+ need(s.asset_version === view.asset.asset_version, 'READ_ASSET_VERSION_MISMATCH');
72
+ const wanted = new Set(s.judgment_ids), ordered = view.ir.catalog.filter(x => wanted.has(x.judgment_id)).map(x => x.judgment_id);
73
+ need(ordered.length === wanted.size, 'READ_SELECTION_NOT_FOUND');
74
+ return mintRequest({ ...record.data, selection: { ...s, judgment_ids: ordered } }, record.sourceDigest);
75
+ }
76
+ function createAuthority(callback, policyJson) {
77
+ if (typeof callback !== 'function') throw new TypeError('PROTECTED_BROWSER_AUTHORITY_CALLBACK');
78
+ const policy = policyJson === undefined ? { requireSignature: false, expectedPublicKeyHex: null } : parseJsonText(policyJson);
79
+ validate('BrowserProtectedSignaturePolicy', policy);
80
+ const token = Object.freeze({}); authorities.set(token, { callback, policy: frozen(policy) }); return token;
81
+ }
82
+ function operation(token) { const record = operations.get(token); return record && !record.disposed ? record : null; }
83
+ function inspectProtectedSnapshot(token) { const record = snapshots.get(token); return record && !record.disposed ? record.view : null; }
84
+ function pairRequest(token, op) {
85
+ const r = requests.get(token), record = operation(op);
86
+ need(r && record && !r.operation);
87
+ r.operation = op; return token;
88
+ }
89
+ function dispose(op) {
90
+ const record = operations.get(op);
91
+ if (!record || record.disposed) return;
92
+ record.disposed = true; record.generation++;
93
+ record.origin.phase = 'closed'; record.origin.view = null; record.origin.metadata = null;
94
+ for (const release of record.releases) release();
95
+ record.releases.clear();
96
+ record.view = null; record.metadata = null;
97
+ }
98
+ function onDispose(op, release) {
99
+ const record = operation(op);
100
+ if (!record) { release(); return () => {}; }
101
+ record.releases.add(release);
102
+ return () => record.releases.delete(release);
103
+ }
104
+ function clock(record, stage) {
105
+ need(!record.disposed, 'PROTECTION_OPERATION_DISPOSED');
106
+ let now;
107
+ try { now = record.metadata.provider.clock(); } catch { need(!record.disposed, 'PROTECTION_OPERATION_DISPOSED'); need(false, 'PROTECTION_PROVIDER_FAILED'); }
108
+ need(!record.disposed, 'PROTECTION_OPERATION_DISPOSED');
109
+ need(strict.uint(now), 'PROTECTION_PROVIDER_FAILED');
110
+ need(now >= record.lastTime, 'PROTECTION_STATE_ROLLBACK');
111
+ record.lastTime = now; return now;
112
+ }
113
+ function receipt(record, now) {
114
+ return frozen({ contract: 'kdna.protected-browser-observation/0.1.0-candidate', operation_id: record.id,
115
+ snapshot_id: record.view.snapshot_id, A: record.view.digests.A.observed, C: record.view.digests.C.observed,
116
+ E: record.view.digests.E.observed, checked_at_ms: now, proof: 'observation_not_authority', provenance: 'host_supplied_triple' });
117
+ }
118
+ function context(record, r, phase, policy) {
119
+ const view = record.view, read_intent = {
120
+ operation: phase, operation_id: record.id, capture_id: record.base.capture.capture_id,
121
+ snapshot_id: view.snapshot_id, request_digest: r.digest, mode: r.data.mode,
122
+ physical_reads: 'none', provenance: 'host_supplied_triple', new_decryption: false,
123
+ new_domain_validation: false, new_signature_verification: false
124
+ };
125
+ return frozen({ request: r.data, request_digest: r.digest, tuple: view.tuple, asset: view.asset,
126
+ digests: view.digests, read_intent, read_intent_digest: digestCanonical(read_intent),
127
+ signature_policy: policy, disclosure: record.metadata.disclosure });
128
+ }
129
+ async function grant(authority, r, record, phase) {
130
+ const a = authorities.get(authority);
131
+ need(a && !record.disposed, 'PROTECTION_OPERATION_UNTRUSTED');
132
+ const integrity = record.metadata.integrity;
133
+ need(!(a.policy.requireSignature || a.policy.expectedPublicKeyHex !== null) ||
134
+ integrity.signature !== 'absent' && (a.policy.expectedPublicKeyHex === null || integrity.public_key === a.policy.expectedPublicKeyHex), 'READ_CORE_INVALID');
135
+ const value = context(record, r, phase, a.policy);
136
+ validate('BrowserProtectedAuthorityContext', value);
137
+ let accepted;
138
+ try { accepted = await a.callback(value); } catch { need(!record.disposed, 'PROTECTION_OPERATION_DISPOSED'); need(false, 'READ_HOST_DENIED'); }
139
+ need(!record.disposed, 'PROTECTION_OPERATION_DISPOSED');
140
+ need(accepted === true, 'READ_HOST_DENIED');
141
+ return value;
142
+ }
143
+ function bind(op, authority, r) {
144
+ const record = operation(op);
145
+ if (!record || !r || r.operation !== op) return null;
146
+ const binding = Object.freeze({
147
+ observe(phase) {
148
+ const task = record.queue.then(async () => {
149
+ try {
150
+ clock(record, phase);
151
+ await grant(authority, r, record, phase);
152
+ const now = clock(record, phase); record.generation++;
153
+ const checkpoint = Object.freeze({}); checkpoints.set(checkpoint, { record, generation: record.generation, phase });
154
+ return Object.freeze({ status: 'current', checkpoint, receipt: receipt(record, now) });
155
+ } catch (e) { return failed(failures.get(e) ?? 'PROTECTION_PROVIDER_FAILED', phase); }
156
+ });
157
+ record.queue = task.then(() => undefined, () => undefined); return task;
158
+ },
159
+ assertCurrent(checkpoint) {
160
+ const cp = checkpoints.get(checkpoint);
161
+ if (!cp || cp.record !== record) return failed();
162
+ try {
163
+ const now = clock(record, cp.phase);
164
+ need(record.generation === cp.generation, 'PROTECTION_STATE_ROLLBACK');
165
+ return Object.freeze({ status: 'current', receipt: receipt(record, now) });
166
+ } catch (e) { return failed(failures.get(e) ?? 'PROTECTION_PROVIDER_FAILED', cp.phase); }
167
+ }
168
+ });
169
+ return { record, binding };
170
+ }
171
+ async function admit(snapshot, admitted, authority) {
172
+ const origin = origins.get(snapshot), raw = request(admitted);
173
+ if (!origin || origin.phase !== 'available' || !raw || raw.operation || raw.data.mode === 'expand' || !authorities.has(authority)) return failed();
174
+ // Consume the genuine origin before any clock/authority callback can reenter.
175
+ origin.phase = 'reserved';
176
+ let op;
177
+ try {
178
+ op = Object.freeze({});
179
+ const nativeSnapshot = Object.freeze({}), metadata = origin.metadata;
180
+ const view = frozen({ ...origin.view, observation: metadata.observation });
181
+ const record = { id: 'browser-protection:' + globalThis.crypto.randomUUID(), origin, view, metadata,
182
+ base: { capture: { capture_id: 'browser-origin:' + globalThis.crypto.randomUUID() } },
183
+ disposed: false, generation: 0, lastTime: 0, queue: Promise.resolve(), releases: new Set() };
184
+ operations.set(op, record); snapshots.set(nativeSnapshot, record);
185
+ need(strict.canonicalJson(raw.data.tuple) === strict.canonicalJson(view.tuple), 'READ_UNSUPPORTED_VERSION');
186
+ const token = normalized(raw, view), r = requests.get(token);
187
+ pairRequest(token, op);
188
+ await grant(authority, r, record, 'admit_retained_protected_snapshot');
189
+ const now = clock(record, 'authorization'); origin.phase = 'active';
190
+ const proof = receipt(record, now); record.receipt = proof;
191
+ return Object.freeze({ status: 'accepted', request: token, snapshot: nativeSnapshot, operation: op,
192
+ receipt: proof, observation: view.observation, disclosure: metadata.disclosure, physical_reads: 'none' });
193
+ } catch (e) {
194
+ dispose(op);
195
+ origin.phase = 'closed'; origin.view = null; origin.metadata = null;
196
+ return failed(failures.get(e) ?? 'READ_CORE_CAPABILITY_UNAVAILABLE', 'authorization');
197
+ }
198
+ }
199
+ module.exports = { C, tuple, frozen, register, mintRequest, request, inspectRequest, normalized, createAuthority,
200
+ operation, inspectSnapshot: inspectProtectedSnapshot, pairRequest, dispose, onDispose, grant, bind, admit };
@@ -2,8 +2,8 @@
2
2
  "candidate_only": true,
3
3
  "source": {
4
4
  "path": "specs/public-semantic-source.json",
5
- "bytes": 1435348,
6
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
5
+ "bytes": 1506884,
6
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
7
7
  },
8
8
  "historical_original_source": {
9
9
  "scope": "historical_original_contract_source_identity_not_current_generator_input",
@@ -2,8 +2,8 @@
2
2
  "candidate_only": true,
3
3
  "source": {
4
4
  "path": "specs/public-semantic-source.json",
5
- "bytes": 1435348,
6
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
5
+ "bytes": 1506884,
6
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
7
7
  },
8
8
  "historical_original_source": {
9
9
  "scope": "historical_original_contract_source_identity_not_current_generator_input",
@@ -3,14 +3,14 @@
3
3
  "candidate_only": true,
4
4
  "source": {
5
5
  "path": "specs/public-semantic-source.json",
6
- "bytes": 1435348,
7
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
6
+ "bytes": 1506884,
7
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
8
8
  },
9
9
  "producer": {
10
10
  "recipe": {
11
11
  "path": "scripts/public-contract/native-output-recipe.json",
12
- "bytes": 155707,
13
- "sha256": "bea4b4a4d426e1b3b23ffb818715712b87114ce32d1db80ab2a24f8efca87a60"
12
+ "bytes": 164001,
13
+ "sha256": "076b8d75b26d3c675fb8f89768e7d3cdddc448f2f29b19adb28b768a0c4dfbfb"
14
14
  },
15
15
  "scripts": [
16
16
  {
@@ -20,8 +20,8 @@
20
20
  },
21
21
  {
22
22
  "path": "scripts/public-contract/native-renderer.mjs",
23
- "bytes": 19534,
24
- "sha256": "05a359837c3c61d18ecc3fe109387ade921daf25eb12a8530e7a5b7550dfe1c7"
23
+ "bytes": 20169,
24
+ "sha256": "44806a5a6dc43b141791b62b3683acd3145ac14b67ee5e6077923c5c62ca0187"
25
25
  },
26
26
  {
27
27
  "path": "scripts/public-contract/generation-writer.mjs",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  {
32
32
  "path": "scripts/public-contract/generate.mjs",
33
- "bytes": 72318,
34
- "sha256": "cd1914a7fd684fc033f635bd331bb5491446222352097fec72dc05982e0e4661"
33
+ "bytes": 73563,
34
+ "sha256": "73f19333a9fbff08480884d8b35ade372fe8b682ea25a77d9b370dc88c740f86"
35
35
  }
36
36
  ]
37
37
  },
@@ -181,7 +181,7 @@
181
181
  {
182
182
  "path": "packages/kdna-core/src/public-contract/creation06/contract.json",
183
183
  "bytes": 71166,
184
- "sha256": "3add833e9d22775b745eed8aaec2ab40872679e7338fa5a704db639f5ca53861"
184
+ "sha256": "bf1bb5bf0b6f3d7d38c2a3c63c413942f377c061bd01eb9b0868a2d9fdca6f8f"
185
185
  },
186
186
  {
187
187
  "path": "packages/kdna-core/src/public-contract/creation06/api.d.ts",
@@ -2,8 +2,8 @@
2
2
  "candidate_only": true,
3
3
  "source": {
4
4
  "path": "specs/public-semantic-source.json",
5
- "bytes": 1435348,
6
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
5
+ "bytes": 1506884,
6
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
7
7
  },
8
8
  "historical_original_source": {
9
9
  "scope": "historical_original_contract_source_identity_not_current_generator_input",
@@ -3,14 +3,14 @@
3
3
  "candidate_only": true,
4
4
  "source": {
5
5
  "path": "specs/public-semantic-source.json",
6
- "bytes": 1435348,
7
- "sha256": "fdcb204c8942ddc10ed5d8d6658a9317102822b5b9c500bc07e5086d5668fc9f"
6
+ "bytes": 1506884,
7
+ "sha256": "a05af27e97be03a8909375217ab353017b72a10532ad7d700b6ae278e30d1d5f"
8
8
  },
9
9
  "producer": {
10
10
  "recipe": {
11
11
  "path": "scripts/public-contract/native-output-recipe.json",
12
- "bytes": 155707,
13
- "sha256": "bea4b4a4d426e1b3b23ffb818715712b87114ce32d1db80ab2a24f8efca87a60"
12
+ "bytes": 164001,
13
+ "sha256": "076b8d75b26d3c675fb8f89768e7d3cdddc448f2f29b19adb28b768a0c4dfbfb"
14
14
  },
15
15
  "scripts": [
16
16
  {
@@ -20,8 +20,8 @@
20
20
  },
21
21
  {
22
22
  "path": "scripts/public-contract/native-renderer.mjs",
23
- "bytes": 19534,
24
- "sha256": "05a359837c3c61d18ecc3fe109387ade921daf25eb12a8530e7a5b7550dfe1c7"
23
+ "bytes": 20169,
24
+ "sha256": "44806a5a6dc43b141791b62b3683acd3145ac14b67ee5e6077923c5c62ca0187"
25
25
  },
26
26
  {
27
27
  "path": "scripts/public-contract/generation-writer.mjs",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  {
32
32
  "path": "scripts/public-contract/generate.mjs",
33
- "bytes": 72318,
34
- "sha256": "cd1914a7fd684fc033f635bd331bb5491446222352097fec72dc05982e0e4661"
33
+ "bytes": 73563,
34
+ "sha256": "73f19333a9fbff08480884d8b35ade372fe8b682ea25a77d9b370dc88c740f86"
35
35
  }
36
36
  ]
37
37
  },
@@ -518,7 +518,7 @@
518
518
  {
519
519
  "path": "packages/kdna-core/src/public-contract/execution06/contract.json",
520
520
  "bytes": 225481,
521
- "sha256": "b12a14fe7966acefecffe19fb4b01666951a1ba378c16181e6a3677f7552980b"
521
+ "sha256": "6fba0f509cb92566eb58d7298f1c58f89badf39b0b0ed37dc09820ce30cff22b"
522
522
  },
523
523
  {
524
524
  "path": "packages/kdna-core/src/public-contract/execution06/api.d.ts",
@@ -809,12 +809,12 @@
809
809
  },
810
810
  "schema_paths": {
811
811
  "CanonicalIR": "specs/canonical-ir-0.6.1.schema.json",
812
- "IssuerResultObservation": "specs/external-grant-issuer-r2-binding-7.schema.json",
812
+ "IssuerResultObservation": "specs/external-grant-issuer-r2-binding-8.schema.json",
813
813
  "Manifest": "schema/manifest-container-0.5.0-judgment-0.5.1.schema.json",
814
814
  "PackageSetNodeSurface": "specs/package-set-node-0.2.1.schema.json",
815
815
  "Payload": "schema/payload-profile-0.5.1.schema.json",
816
- "ProtectedSourceObservation": "specs/protected-source-r2-binding-7.schema.json",
817
- "ProtectionDefinitionObservation": "specs/protection-admission-r2-binding-7.schema.json",
816
+ "ProtectedSourceObservation": "specs/protected-source-r2-binding-8.schema.json",
817
+ "ProtectionDefinitionObservation": "specs/protection-admission-r2-binding-8.schema.json",
818
818
  "PublicAgentHostReceipt": "schema/agent-host-receipt-0.3.1.schema.json",
819
819
  "PublicAgentHostRequest": "schema/agent-host-request-0.3.1.schema.json",
820
820
  "PublicConsumptionPlan": "schema/consumption-plan-0.3.1.schema.json",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "api_typescript": "export type IssuerSecrets = { readonly issuerRootKey: Uint8Array; readonly issuerSigningPrivateKeyPkcs8: Uint8Array; readonly signaturePolicy: IssuerSignaturePolicy };\nexport type IssuanceResult = (IssuerIssuedObservation & { readonly grantBytes: Uint8Array }) | IssuerCoreRejectedObservation | IssuerFailedObservation;\nexport declare function getExternalGrantIssuerContract(): IssuerDescriptor;\nexport declare function issueExternalKeyGrantForAsset(input: string | Uint8Array, options: IssuerOptions, secrets: IssuerSecrets): Promise<IssuanceResult>;\n",
3
- "definition_digest": "sha256:eedb408131beb2769f8791c6372b70cf0df2dbfffc2e017d3933d52898483ae5",
3
+ "definition_digest": "sha256:33e91624bc825ccdbbd7b0e85f961f0b455bb72cabd1fac6397f1e3fee319329",
4
4
  "derived_runtime_enforcement": {
5
5
  "ISSUER-AUTHENTICATION": {
6
6
  "generator_machine_check": "none",
@@ -384,8 +384,8 @@
384
384
  "runtime_not_implemented": [],
385
385
  "schema_binding": {
386
386
  "package_versions": {
387
- "@aikdna/kdna-core": "0.36.0",
388
- "@aikdna/kdna-read": "0.11.0"
387
+ "@aikdna/kdna-core": "0.37.1-rc.browser.1",
388
+ "@aikdna/kdna-read": "0.11.2-rc.browser.1"
389
389
  },
390
390
  "version_tuple": {
391
391
  "container": "0.5.0",
@@ -400,8 +400,8 @@
400
400
  "trace": "kdna.judgment-trace/0.3.1"
401
401
  }
402
402
  },
403
- "schema_id": "urn:kdna:schema:external-grant-issuer:1.0.0:binding:r2:7",
404
- "schema_path": "specs/external-grant-issuer-r2-binding-7.schema.json",
403
+ "schema_id": "urn:kdna:schema:external-grant-issuer:1.0.0:binding:r2:8",
404
+ "schema_path": "specs/external-grant-issuer-r2-binding-8.schema.json",
405
405
  "status": "IMPLEMENTATION_CANDIDATE_NOT_ACCEPTED",
406
406
  "types": {
407
407
  "IssuerAdmissionObservation": {
@@ -543,7 +543,7 @@
543
543
  "type": "string"
544
544
  },
545
545
  "version": {
546
- "const": "0.36.0",
546
+ "const": "0.37.1-rc.browser.1",
547
547
  "type": "string"
548
548
  }
549
549
  },