@githolon/dsl 0.113.1 → 0.113.3
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/dart/CHANGELOG.md +5 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +14 -2
- package/dart/lib/src/runner/node-entry.mjs +95 -40
- package/dart/pubspec.yaml +1 -1
- package/dart/test/workspace_preparation_upkeep_test.dart +32 -3
- package/package.json +2 -2
- package/src/compile_package_main.ts +2 -2
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 0.67.1
|
|
2
|
+
|
|
3
|
+
- Git custody upkeep backing off after a failure is reported as `upkeepRetrying`, not `retrying`: the workspace is
|
|
4
|
+
ready meanwhile, so it no longer shows as a sync problem (CAP-693).
|
|
5
|
+
|
|
1
6
|
## 0.67.0
|
|
2
7
|
|
|
3
8
|
- A write sent over the live link has its receipt converge on the custodian's admission: the live desk reports the
|
|
@@ -23,6 +23,7 @@ final class WorkspacePreparationReport {
|
|
|
23
23
|
this.sqliteFrontier,
|
|
24
24
|
this.retryAfterMillis,
|
|
25
25
|
this.stopped = false,
|
|
26
|
+
this.upkeep = false,
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
final WorkspacePreparationStep step;
|
|
@@ -32,7 +33,16 @@ final class WorkspacePreparationReport {
|
|
|
32
33
|
final String? sqliteFrontier;
|
|
33
34
|
final int? retryAfterMillis;
|
|
34
35
|
final bool stopped;
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
/// Git custody upkeep after this peer's own writes: it never holds a read or a write.
|
|
38
|
+
final bool upkeep;
|
|
39
|
+
|
|
40
|
+
/// Preparation the workspace is waiting on is backing off after a failure. Upkeep retrying
|
|
41
|
+
/// is not: the workspace is ready meanwhile, and nothing the user can do changes it (CAP-693).
|
|
42
|
+
bool get retrying => retryAfterMillis != null && !upkeep;
|
|
43
|
+
|
|
44
|
+
/// Upkeep backing off after a failure, for diagnostics; never shown as a sync problem.
|
|
45
|
+
bool get upkeepRetrying => retryAfterMillis != null && upkeep;
|
|
36
46
|
|
|
37
47
|
/// Exact equality of reported frontiers, rather than a guess from residency.
|
|
38
48
|
bool? get sqliteCurrent {
|
|
@@ -81,7 +91,8 @@ final class WorkspacePreparationReport {
|
|
|
81
91
|
final upkeep = step == WorkspacePreparationStep.preparingCustody ||
|
|
82
92
|
(kernel == null &&
|
|
83
93
|
progress.cause ==
|
|
84
|
-
protocol.ReadMaintenanceCause
|
|
94
|
+
protocol.ReadMaintenanceCause
|
|
95
|
+
.READ_MAINTENANCE_CAUSE_ADMITTED_OFFER);
|
|
85
96
|
return WorkspacePreparationReport(
|
|
86
97
|
step: step,
|
|
87
98
|
active: retry == null &&
|
|
@@ -91,6 +102,7 @@ final class WorkspacePreparationReport {
|
|
|
91
102
|
(kernel == null || kernel.maintenancePending),
|
|
92
103
|
retryAfterMillis: retry,
|
|
93
104
|
stopped: progress.stopped,
|
|
105
|
+
upkeep: upkeep,
|
|
94
106
|
// A new demand may target a newer frontier. Never carry old readiness
|
|
95
107
|
// across its scheduled observation before the kernel reports a result.
|
|
96
108
|
gitFrontier: kernel == null
|
|
@@ -14587,6 +14587,32 @@ var KernelPort = class {
|
|
|
14587
14587
|
// ../src/runtime/placement_desk.ts
|
|
14588
14588
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
14589
14589
|
|
|
14590
|
+
// ../src/runtime/http_origin.ts
|
|
14591
|
+
init_define_NOMOS_KERNEL_RELEASE();
|
|
14592
|
+
var AUTHORITY = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)/i;
|
|
14593
|
+
var DEFAULT_PORTS = { http: "80", https: "443" };
|
|
14594
|
+
function httpOrigin(url) {
|
|
14595
|
+
const match = AUTHORITY.exec(url.trim());
|
|
14596
|
+
if (!match) return void 0;
|
|
14597
|
+
const scheme = match[1].toLowerCase();
|
|
14598
|
+
if (scheme !== "http" && scheme !== "https") return void 0;
|
|
14599
|
+
const authority = match[2];
|
|
14600
|
+
const hostAndPort = authority.slice(authority.lastIndexOf("@") + 1);
|
|
14601
|
+
const ipv6 = /^(\[[0-9a-f:.]+\])(?::(\d*))?$/i.exec(hostAndPort);
|
|
14602
|
+
const named = /^([^:[\]\s]+)(?::(\d*))?$/.exec(hostAndPort);
|
|
14603
|
+
const parts = ipv6 ?? named;
|
|
14604
|
+
if (!parts) return void 0;
|
|
14605
|
+
const host = parts[1].toLowerCase();
|
|
14606
|
+
if (host.length === 0 || /[\s<>^`{|}%\\]/.test(host)) return void 0;
|
|
14607
|
+
let port = parts[2] ?? "";
|
|
14608
|
+
if (port !== "") {
|
|
14609
|
+
const value = Number(port);
|
|
14610
|
+
if (!Number.isInteger(value) || value > 65535) return void 0;
|
|
14611
|
+
port = String(value);
|
|
14612
|
+
}
|
|
14613
|
+
return port === "" || port === DEFAULT_PORTS[scheme] ? `${scheme}://${host}` : `${scheme}://${host}:${port}`;
|
|
14614
|
+
}
|
|
14615
|
+
|
|
14590
14616
|
// ../src/runtime/provider_origins.ts
|
|
14591
14617
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
14592
14618
|
|
|
@@ -14926,14 +14952,7 @@ var normalizeProfile = (profile) => {
|
|
|
14926
14952
|
...servedOrigin === void 0 ? {} : { servedOrigin }
|
|
14927
14953
|
});
|
|
14928
14954
|
};
|
|
14929
|
-
var originOf2 =
|
|
14930
|
-
try {
|
|
14931
|
-
const parsed = new URL(url);
|
|
14932
|
-
return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.origin : void 0;
|
|
14933
|
-
} catch {
|
|
14934
|
-
return void 0;
|
|
14935
|
-
}
|
|
14936
|
-
};
|
|
14955
|
+
var originOf2 = httpOrigin;
|
|
14937
14956
|
var ReplicaPlacementDirectiveKind = Object.freeze({
|
|
14938
14957
|
None: "none",
|
|
14939
14958
|
Cache: "cache",
|
|
@@ -20783,7 +20802,10 @@ var ReadMaintenanceDesk = class {
|
|
|
20783
20802
|
...background ? { background } : {},
|
|
20784
20803
|
...awaited || existing?.awaited ? { awaited: true } : {},
|
|
20785
20804
|
failures: existing?.failures ?? 0,
|
|
20786
|
-
|
|
20805
|
+
// A foreground read may retry at once. Upkeep owed by a write or a sync keeps any back-off
|
|
20806
|
+
// it is already serving: otherwise every write retried a failing upkeep immediately, and a
|
|
20807
|
+
// workspace whose upkeep could not succeed retried on every write (CAP-693).
|
|
20808
|
+
retryNotBeforeNanoseconds: isReadDemand ? 0n : existing?.retryNotBeforeNanoseconds ?? 0n
|
|
20787
20809
|
});
|
|
20788
20810
|
if (isReadDemand && (!existing?.read || existing.read.owedByAdvance)) {
|
|
20789
20811
|
const entries = [...this.#pending.entries()];
|
|
@@ -21392,18 +21414,17 @@ var SubscriptionManager = class {
|
|
|
21392
21414
|
#requestReadMaintenance;
|
|
21393
21415
|
#clock;
|
|
21394
21416
|
#subscriptions = /* @__PURE__ */ new Map();
|
|
21395
|
-
/** Watches owed a re-read, drained one query group per
|
|
21417
|
+
/** Watches owed a re-read, drained one query group per office turn (see [drainOwedTurn]). */
|
|
21396
21418
|
#owed = /* @__PURE__ */ new Set();
|
|
21397
|
-
#
|
|
21398
|
-
#draining = false;
|
|
21419
|
+
#deferRefreshes;
|
|
21399
21420
|
#sequence = 0n;
|
|
21400
|
-
constructor(queries, sessions, events, requestReadMaintenance, clock,
|
|
21421
|
+
constructor(queries, sessions, events, requestReadMaintenance, clock, deferRefreshes = false) {
|
|
21401
21422
|
this.#queries = queries;
|
|
21402
21423
|
this.#sessions = sessions;
|
|
21403
21424
|
this.#events = events;
|
|
21404
21425
|
this.#requestReadMaintenance = requestReadMaintenance;
|
|
21405
21426
|
this.#clock = clock;
|
|
21406
|
-
this.#
|
|
21427
|
+
this.#deferRefreshes = deferRefreshes;
|
|
21407
21428
|
}
|
|
21408
21429
|
start(request, command) {
|
|
21409
21430
|
if (!command.subscriptionId) throw new Error("watch requires a subscription identity");
|
|
@@ -21509,34 +21530,33 @@ var SubscriptionManager = class {
|
|
|
21509
21530
|
* or replace current authorization. Each watch still owns its delivery state.
|
|
21510
21531
|
*/
|
|
21511
21532
|
#refreshMatching(matches, cause) {
|
|
21512
|
-
if (this.#
|
|
21533
|
+
if (this.#deferRefreshes && !cause) {
|
|
21513
21534
|
for (const [id, subscription] of this.#subscriptions) {
|
|
21514
21535
|
if (subscription.request.query && matches(subscription)) this.#owed.add(id);
|
|
21515
21536
|
}
|
|
21516
|
-
this.#drain();
|
|
21517
21537
|
return;
|
|
21518
21538
|
}
|
|
21519
21539
|
this.#refreshGroups(this.#groups(matches), cause);
|
|
21520
21540
|
}
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
this.#
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
|
|
21537
|
-
|
|
21538
|
-
|
|
21539
|
-
|
|
21541
|
+
/** Whether any watch is owed a re-read: the office's next drive() is due at once. */
|
|
21542
|
+
get owesRefresh() {
|
|
21543
|
+
return this.#owed.size > 0;
|
|
21544
|
+
}
|
|
21545
|
+
/** One office turn of owed re-reads: the first owed watch's query group. False when none was owed. */
|
|
21546
|
+
drainOwedTurn() {
|
|
21547
|
+
if (this.#owed.size === 0) return false;
|
|
21548
|
+
const first = this.#owed.values().next().value;
|
|
21549
|
+
const lead = this.#subscriptions.get(first);
|
|
21550
|
+
if (!lead?.request.query) {
|
|
21551
|
+
this.#owed.delete(first);
|
|
21552
|
+
return true;
|
|
21553
|
+
}
|
|
21554
|
+
const declaration = toBinary(QueryRequestSchema, lead.request.query);
|
|
21555
|
+
const session = lead.request.session;
|
|
21556
|
+
const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary(QueryRequestSchema, subscription.request.query), declaration));
|
|
21557
|
+
for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
|
|
21558
|
+
this.#refreshGroups(group);
|
|
21559
|
+
return true;
|
|
21540
21560
|
}
|
|
21541
21561
|
#groups(matches) {
|
|
21542
21562
|
const groups = [];
|
|
@@ -21660,6 +21680,39 @@ function createSyntheticRequest(requestId) {
|
|
|
21660
21680
|
});
|
|
21661
21681
|
}
|
|
21662
21682
|
|
|
21683
|
+
// ../src/runtime/shell_contract.ts
|
|
21684
|
+
init_define_NOMOS_KERNEL_RELEASE();
|
|
21685
|
+
var SHELL_CONTRACT_V1 = Object.freeze({
|
|
21686
|
+
version: 1,
|
|
21687
|
+
/** Host globals beyond ECMAScript 2022, which every shell supplies. */
|
|
21688
|
+
host: Object.freeze(["TextEncoder", "TextDecoder", "queueMicrotask", "console"]),
|
|
21689
|
+
/** Nomos bridges a native bootstrap installs for the ports it hands to peerOffice.open. */
|
|
21690
|
+
bridges: Object.freeze([
|
|
21691
|
+
"__nomosKernel",
|
|
21692
|
+
"__nomosCredentialVault",
|
|
21693
|
+
"__nomosProfile",
|
|
21694
|
+
"__nomosObservations",
|
|
21695
|
+
"__nomosCustodyStorage",
|
|
21696
|
+
"__nomosPeerDeskStore",
|
|
21697
|
+
"__nomosSyncDiagnostic",
|
|
21698
|
+
"__nomosShellContract"
|
|
21699
|
+
]),
|
|
21700
|
+
/** Globals the runtime may only probe: used behind their own `typeof` test, never bare. */
|
|
21701
|
+
probed: Object.freeze(["process", "Deno", "Bun", "define"])
|
|
21702
|
+
});
|
|
21703
|
+
var SHELL_CONTRACT_V2 = Object.freeze({ ...SHELL_CONTRACT_V1, version: 2 });
|
|
21704
|
+
var SHELL_CONTRACT_MINIMUM = 1;
|
|
21705
|
+
function declaredShellContract(scope = globalThis) {
|
|
21706
|
+
const declared = scope.__nomosShellContract;
|
|
21707
|
+
return declared === void 0 ? 1 : Number(declared);
|
|
21708
|
+
}
|
|
21709
|
+
function assertShellContract(scope = globalThis) {
|
|
21710
|
+
const declared = declaredShellContract(scope);
|
|
21711
|
+
if (!Number.isInteger(declared) || declared < SHELL_CONTRACT_MINIMUM) {
|
|
21712
|
+
throw new Error(`nomos.runtime.shell_contract_unsupported: this runtime needs shell contract ${SHELL_CONTRACT_MINIMUM} or later; the shell declares ${String(declared)}`);
|
|
21713
|
+
}
|
|
21714
|
+
}
|
|
21715
|
+
|
|
21663
21716
|
// ../src/runtime/replica_follow_controller.ts
|
|
21664
21717
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
21665
21718
|
|
|
@@ -29657,10 +29710,9 @@ var PeerOffice = class {
|
|
|
29657
29710
|
this.#trace,
|
|
29658
29711
|
(session) => this.#readMaintenance.schedule(session, ReadMaintenanceCause.READ_DEBT),
|
|
29659
29712
|
observations,
|
|
29660
|
-
// An interactive peer keeps its thread responsive while watches catch up
|
|
29661
|
-
|
|
29662
|
-
|
|
29663
|
-
} : void 0
|
|
29713
|
+
// An interactive peer keeps its thread responsive while watches catch up: owed re-reads
|
|
29714
|
+
// wait for its drive() turns.
|
|
29715
|
+
this.#interactivePeer
|
|
29664
29716
|
);
|
|
29665
29717
|
this.#application = new ApplicationDesk({
|
|
29666
29718
|
onAdmitted: (session) => {
|
|
@@ -30067,7 +30119,9 @@ var PeerOffice = class {
|
|
|
30067
30119
|
* mirrors queue/backoff state.
|
|
30068
30120
|
*/
|
|
30069
30121
|
drive() {
|
|
30070
|
-
|
|
30122
|
+
if (this.#subscriptions.drainOwedTurn()) return 0n;
|
|
30123
|
+
const wake = this.#maintenance.drive();
|
|
30124
|
+
return this.#subscriptions.owesRefresh ? 0n : wake;
|
|
30071
30125
|
}
|
|
30072
30126
|
/**
|
|
30073
30127
|
* Carry one exact maintenance demand through a durable host continuation.
|
|
@@ -31028,6 +31082,7 @@ var PeerOffice = class {
|
|
|
31028
31082
|
};
|
|
31029
31083
|
var peerOffice = {
|
|
31030
31084
|
open(kernel, credentials, profile, observations, custodyStorage, peerDeskStore) {
|
|
31085
|
+
assertShellContract();
|
|
31031
31086
|
return new PeerOffice(kernel, credentials, profile, observations, custodyStorage, peerDeskStore);
|
|
31032
31087
|
},
|
|
31033
31088
|
Peer: PeerOffice
|
package/dart/pubspec.yaml
CHANGED
|
@@ -7,7 +7,7 @@ repository: https://github.com/Captain-App/nomos2
|
|
|
7
7
|
description: >-
|
|
8
8
|
Nomos 2 Dart client — generated domain values, intent payloads and application
|
|
9
9
|
lifecycle types over the typed Nomos kernel protocol and USDA custody model.
|
|
10
|
-
version: 0.67.
|
|
10
|
+
version: 0.67.1
|
|
11
11
|
|
|
12
12
|
environment:
|
|
13
13
|
sdk: ^3.5.0
|
|
@@ -7,7 +7,8 @@ void main() {
|
|
|
7
7
|
final packing = WorkspacePreparationReport.fromMaintenance(
|
|
8
8
|
protocol.ReadMaintenanceProgress(
|
|
9
9
|
workspace: 'estate',
|
|
10
|
-
cause:
|
|
10
|
+
cause:
|
|
11
|
+
protocol.ReadMaintenanceCause.READ_MAINTENANCE_CAUSE_ADMITTED_OFFER,
|
|
11
12
|
kernel: protocol.MaintenanceQuantumResponse(
|
|
12
13
|
phase: protocol.MaintenancePhase.MAINTENANCE_PHASE_GIT_CUSTODY,
|
|
13
14
|
maintenancePending: true,
|
|
@@ -20,7 +21,8 @@ void main() {
|
|
|
20
21
|
final scheduled = WorkspacePreparationReport.fromMaintenance(
|
|
21
22
|
protocol.ReadMaintenanceProgress(
|
|
22
23
|
workspace: 'estate',
|
|
23
|
-
cause:
|
|
24
|
+
cause:
|
|
25
|
+
protocol.ReadMaintenanceCause.READ_MAINTENANCE_CAUSE_ADMITTED_OFFER,
|
|
24
26
|
),
|
|
25
27
|
);
|
|
26
28
|
expect(scheduled.active, isFalse);
|
|
@@ -35,6 +37,33 @@ void main() {
|
|
|
35
37
|
),
|
|
36
38
|
),
|
|
37
39
|
);
|
|
38
|
-
expect(reads.active, isTrue,
|
|
40
|
+
expect(reads.active, isTrue,
|
|
41
|
+
reason: 'a read index still being built is real preparation');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('upkeep backing off after a failure is not a sync problem (CAP-693)',
|
|
45
|
+
() {
|
|
46
|
+
// A shallow device's Git upkeep was refused by the kernel; the status turned orange though
|
|
47
|
+
// every read and write still worked.
|
|
48
|
+
final failingUpkeep = WorkspacePreparationReport.fromMaintenance(
|
|
49
|
+
protocol.ReadMaintenanceProgress(
|
|
50
|
+
workspace: 'estate',
|
|
51
|
+
cause:
|
|
52
|
+
protocol.ReadMaintenanceCause.READ_MAINTENANCE_CAUSE_ADMITTED_OFFER,
|
|
53
|
+
retryAfterMillis: 4000,
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
expect(failingUpkeep.retrying, isFalse);
|
|
57
|
+
expect(failingUpkeep.upkeepRetrying, isTrue);
|
|
58
|
+
|
|
59
|
+
final failingReads = WorkspacePreparationReport.fromMaintenance(
|
|
60
|
+
protocol.ReadMaintenanceProgress(
|
|
61
|
+
workspace: 'estate',
|
|
62
|
+
cause: protocol.ReadMaintenanceCause.READ_MAINTENANCE_CAUSE_OPEN,
|
|
63
|
+
retryAfterMillis: 4000,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
expect(failingReads.retrying, isTrue,
|
|
67
|
+
reason: 'preparation a read waits on still shows');
|
|
39
68
|
});
|
|
40
69
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.113.
|
|
3
|
+
"version": "0.113.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"test": "vitest run"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@githolon/runtime": "^0.113.
|
|
76
|
+
"@githolon/runtime": "^0.113.3",
|
|
77
77
|
"@bufbuild/protobuf": "^2.13.0",
|
|
78
78
|
"@bufbuild/protoc-gen-es": "^2.13.0",
|
|
79
79
|
"esbuild": "0.24.2",
|
|
@@ -2543,8 +2543,8 @@ const NOMOS_TYPES_DEP = "^0.12.0";
|
|
|
2543
2543
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
2544
2544
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
2545
2545
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
2546
|
-
const NOMOS_CLIENT_DEP = "^0.67.
|
|
2547
|
-
const NOMOS_FLUTTER_DEP = "^0.66.
|
|
2546
|
+
const NOMOS_CLIENT_DEP = "^0.67.1";
|
|
2547
|
+
const NOMOS_FLUTTER_DEP = "^0.66.3";
|
|
2548
2548
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in the Dart and Flutter
|
|
2549
2549
|
// package pubspecs — a release without this bump fails the suite, so tenants never
|
|
2550
2550
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|