@githolon/dsl 0.34.0 → 0.34.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "type": "module",
5
5
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -1835,6 +1835,13 @@ function emitDirective(
1835
1835
  const ctorParams = specs
1836
1836
  .map((s) => ` ${s.optional ? "" : "required "}this.${s.name},`)
1837
1837
  .join("\n");
1838
+ // Zero-field payload (e.g. a `.births()` sanctioning directive with an empty
1839
+ // object schema): `const X({});` / a dangling blank field block is INVALID Dart —
1840
+ // emit a plain `const X();` and an empty map literal instead.
1841
+ const hasFields = specs.length > 0;
1842
+ const ctorLines = hasFields
1843
+ ? [` const ${className}({`, ctorParams, ` });`]
1844
+ : [` const ${className}();`];
1838
1845
 
1839
1846
  // toPayloadJson: serialise only typed fields to data. No Event, no Hlc; the
1840
1847
  // GitHolon executes the installed domain plan. Optional
@@ -1870,12 +1877,9 @@ function emitDirective(
1870
1877
  ` /// The referential marker (creates/mutates/ensures/archives).`,
1871
1878
  ` static const String marker = '${d.marker}';`,
1872
1879
  ``,
1873
- fieldDecls,
1874
- ``,
1880
+ ...(hasFields ? [fieldDecls, ``] : []),
1875
1881
  ` /// ${docFirst}`,
1876
- ` const ${className}({`,
1877
- ctorParams,
1878
- ` });`,
1882
+ ...ctorLines,
1879
1883
  ``,
1880
1884
  ` @override`,
1881
1885
  ` String get domain => domainName;`,
@@ -1766,9 +1766,10 @@ function v2IdentityAndCleanupPreamble(opts: TsProofOptions, hashConst: string, n
1766
1766
  }
1767
1767
 
1768
1768
  /**
1769
- * THE V2 CATCH/FINALLY (G1, gap 4): retire the throwaway workspace on every exit via the OPEN lane (no
1770
- * Bearer — there is no host secret to present; a retire is a SIGNED governance offer in the real lane, but
1771
- * the open self-retire suffices to clean up a throwaway). PROOF_KEEP=1 keeps it.
1769
+ * THE V2 CATCH/FINALLY (G1, gap 4 · 0.34.1): retirement is a SIGNED governance offer — the open self-retire
1770
+ * lane is DEAD post-warrant-flip, so the proof itself never retires. Under `githolon proof --live`
1771
+ * (NOMOS_PROOF_MANAGED=1) the CLI created the workspace REGISTERED and retires it lawfully after exit;
1772
+ * standalone, the proof warns LOUDLY and names the manual command. PROOF_KEEP=1 keeps it.
1772
1773
  */
1773
1774
  function v2CatchFinally(): string[] {
1774
1775
  return [
@@ -1776,13 +1777,18 @@ function v2CatchFinally(): string[] {
1776
1777
  ` runError = e;`,
1777
1778
  ` console.error("✗ " + ((e as Error)?.message ?? e));`,
1778
1779
  `} finally {`,
1779
- ` // THE CLEANUP CONTRACT: never an orphaned cloud workspace. Retired on every exit path (open lane — no`,
1780
- ` // host secret exists post-G1); PROOF_KEEP=1 keeps it and prints the persist command.`,
1780
+ ` // THE CLEANUP CONTRACT: never a SILENTLY orphaned cloud workspace. Retirement is a SIGNED`,
1781
+ ` // governance offer (retireOwnWorkspace at the parent) — the old open-lane POST /retire is dead`,
1782
+ ` // post-warrant-flip. \`githolon proof --live\` orchestrates it (NOMOS_PROOF_MANAGED=1: it created`,
1783
+ ` // the workspace REGISTERED and retires it after this process exits). Run standalone, this proof`,
1784
+ ` // cannot lawfully retire (no signing key) — so it says so LOUDLY and names the exact command.`,
1781
1785
  ` if (born_ws && process.env.PROOF_KEEP === "1") {`,
1782
1786
  ` console.log(\`workspace \${WS} KEPT — retire it when done: githolon ws retire \${WS}\`);`,
1787
+ ` } else if (born_ws && process.env.NOMOS_PROOF_MANAGED === "1") {`,
1788
+ ` console.log(\` workspace \${WS} — retirement handled by githolon proof --live (signed retireOwnWorkspace)\`);`,
1783
1789
  ` } else if (born_ws) {`,
1784
- ` const rr = await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/retire\`, { method: "POST", headers: { "x-nomos-principal": PRINCIPAL } }).then((x) => x.json()).catch(() => ({}));`,
1785
- ` console.log(\` retired \${WS}: \${(rr as { ok?: boolean }).ok === true}\`);`,
1790
+ ` console.error(\`⚠ THROWAWAY WORKSPACE NOT RETIRED: \${WS} (retirement is a signed governance offer this standalone proof cannot author)\`);`,
1791
+ ` console.error(\`⚠ retire it manually: githolon ws retire \${WS} (run the managed lane next time: githolon proof --live)\`);`,
1786
1792
  ` }`,
1787
1793
  ` process.exit(runError ? 1 : 0);`,
1788
1794
  `}`,
@@ -356,8 +356,19 @@ const DART_SUPPORT_SRC = [
356
356
  // The async WebView bridge runtime (NomosBridge / BridgeTransport) the generated
357
357
  // `<name>.client.dart` drives — the barrel re-exports it, so it must be vendored too.
358
358
  "webview_bridge.dart",
359
+ // Typed diagnostics (nomosErrorFromInfo / MissingOfferAuthority / …) — the vendored
360
+ // bridge AND the generated `<name>.client.dart` reference these through the barrel,
361
+ // so skipping it left `dart analyze` red on every vendored output (0.34.1). No
362
+ // external pub deps.
363
+ "errors.dart",
359
364
  ] as const;
360
365
 
366
+ /** Barrel exports DROPPED in vendored mode: `schema_validation.dart` (drags the external
367
+ * `json_schema` pub dep) and `home.dart` (the home-onboarding runtime — drags
368
+ * `package:crypto`; nothing the codegen emits references it). Package-import mode
369
+ * (a real `nomos_client` pub dep) keeps the full barrel. */
370
+ const VENDORED_BARREL_EXCLUDES = ["src/schema_validation.dart", "src/home.dart"] as const;
371
+
361
372
  function removeVendoredDartSupport(dartOut: string): void {
362
373
  rmSync(path.join(dartOut, "nomos_client.dart"), { force: true });
363
374
  rmSync(path.join(dartOut, "src"), { recursive: true, force: true });
@@ -385,7 +396,7 @@ function emitDart(
385
396
  const libDir = path.join(DSL_DIR, "dart", "lib");
386
397
  const barrel = readFileSync(path.join(libDir, "nomos_client.dart"), "utf8")
387
398
  .split("\n")
388
- .filter((line) => !line.includes("src/schema_validation.dart"))
399
+ .filter((line) => !VENDORED_BARREL_EXCLUDES.some((x) => line.includes(x)))
389
400
  .join("\n");
390
401
  writeFileSync(path.join(dartOut, "nomos_client.dart"), barrel, "utf8");
391
402
  for (const f of DART_SUPPORT_SRC) {
@@ -850,12 +850,17 @@ export const retireOwnOnly = workspaceInvariant("RetireOwnOnly")
850
850
  ])
851
851
  .assert((refs, ctx) => {
852
852
  const target = (refs as { target?: { principal?: string; createdBy?: string } }).target;
853
- const author = ctx?.principal ?? "";
853
+ // The captured, VERIFIED author rides as a SUBJECT (`user:<uid>`); the record's creator fields
854
+ // (`principal`/`createdBy`, stamped at createWorkspace/birth) are the BARE uid — normalize the
855
+ // prefix before comparing (0.34.1: the raw compare could never match, so retireOwnWorkspace
856
+ // refused its own creator).
857
+ const bare = (s: string): string => (s.startsWith("user:") ? s.slice(5) : s);
858
+ const author = bare(ctx?.principal ?? "");
854
859
  // The captured, VERIFIED author must equal the record's recorded creator (its `principal`/`createdBy`,
855
860
  // set by the same identity at createWorkspace). So a creator may retire ONLY its own workspaces.
856
861
  return author &&
857
- ((target?.principal && target.principal === author) ||
858
- (target?.createdBy && target.createdBy === author))
862
+ ((target?.principal && bare(target.principal) === author) ||
863
+ (target?.createdBy && bare(target.createdBy) === author))
859
864
  ? { accept: true }
860
865
  : { reject: "retire-own-only: only the workspace's creator may retire it" };
861
866
  });