@githolon/dsl 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
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",
@@ -32,8 +32,14 @@ import { directive } from "../directive.js";
32
32
  import { create } from "../authoring.js";
33
33
  import { set, type PlannedOp } from "../ops.js";
34
34
  import { query } from "../query.js";
35
+ import { workspaceInvariant, refAs } from "./workspace_invariant.js";
35
36
  import { identityRelations } from "./signing_identity.js";
36
37
 
38
+ // `nomos.sha256` — the TRUSTLESS, pure hash computed IN the githolon (Rust sha2 bound in the sealed engine;
39
+ // see deterministic-rquickjs). Available as a global to plans + invariant predicates (like `nomos.mint`); it
40
+ // lets the home law re-derive `home-<hash(owner)>` itself, so the SQUAT invariant runs in-law on every peer.
41
+ declare const nomos: { sha256(input: string): string };
42
+
37
43
  /** The KEY DIRECTORY is the `signer` relation — re-exported so a home holon's law composes it (the
38
44
  * identity's public device keys, enrolled via `enrollSigner`, checked by the gate). */
39
45
  export { identityRelations };
@@ -47,30 +53,58 @@ export { identityRelations };
47
53
  * `seedHomeOwner`, kept off the open session lane), so a tenant cannot forge ownership.
48
54
  */
49
55
  export const HOME_OWNER_ID = "home-owner:self";
56
+ /** A home holon's SELF-COMMITTED NAME prefix — `home-<sha256(subject)>` (the client's `homeNameOf` + the
57
+ * squat invariant both derive it). The home's chain commits to its own routing name, so the bailiff can
58
+ * bind the name to the CONTENT (custody) while the LAW guarantees the name hashes its owner. */
59
+ export const HOME_NAME_PREFIX = "home-";
60
+ export const HOME_NAME_HASH_LEN = 40;
50
61
  export const HomeOwner = aggregate("HomeOwner", {
51
62
  /** The identity this home belongs to — the canonical `user:<uid>` subject the §3 gate binds quotes to. */
52
63
  principal: t.string().merge(Lww),
64
+ /** THE HOME'S SELF-COMMITTED NAME (`home-<sha256(principal)>`) — the squat invariant asserts it hashes the
65
+ * owner, so the chain's claimed name can ONLY be its rightful owner's slot (home_holons §5). */
66
+ homeName: t.string().merge(Lww),
53
67
  /** ISO-8601, caller-stamped (determinism — no clock in the plan). */
54
68
  bornAt: t.string().merge(Lww),
55
69
  });
56
70
 
57
- /** The framework PRIMITIVE plan: stamp the home's owner (singleton at the fixed id the gate reads). */
58
- export function writeHomeOwner(p: { principal: string; bornAt: string }): PlannedOp[] {
71
+ /** The framework PRIMITIVE plan: stamp the home's owner + its self-committed name (singleton at the fixed id). */
72
+ export function writeHomeOwner(p: { principal: string; homeName: string; bornAt: string }): PlannedOp[] {
59
73
  const h = instance(HomeOwner, HOME_OWNER_ID);
60
- return [set(h, "principal", p.principal), set(h, "bornAt", p.bornAt)];
74
+ return [set(h, "principal", p.principal), set(h, "homeName", p.homeName), set(h, "bornAt", p.bornAt)];
61
75
  }
62
76
 
63
77
  /**
64
- * `seedHomeOwner` — the birth-door directive that stamps the home's owner at the fixed singleton id. A
65
- * CONTROL-PLANE write: the host authors it once at lazy birth (after resolving who the home is for); the
66
- * open session lane structurally REFUSES it (by directive id, like the §6 handoff seals), so a tenant
67
- * cannot overwrite ownership. `.ensures` (a deterministic-keyed singleton, not a minted record).
78
+ * `seedHomeOwner` — the birth-door directive that stamps the home's owner + its self-committed `homeName` at
79
+ * the fixed singleton id. A CONTROL-PLANE write: the host authors it once at lazy birth; the open session
80
+ * lane structurally REFUSES it (by directive id). `.ensures` (a deterministic-keyed singleton). The `homeName`
81
+ * is caller-supplied but the {@link homeNameBindsOwner} invariant proves it `== home-<sha256(principal)>`,
82
+ * so a squatter cannot claim a name slot that doesn't hash to ITS own owner.
68
83
  */
69
84
  export const seedHomeOwner = directive("seedHomeOwner")
70
85
  .ensures(HomeOwner)
71
- .payload(z.object({ principal: z.string().min(1), bornAt: z.string().min(1) }))
86
+ .payload(z.object({ principal: z.string().min(1), homeName: z.string().min(1), bornAt: z.string().min(1) }))
72
87
  .plan((p) => writeHomeOwner(p));
73
88
 
89
+ /**
90
+ * THE SQUAT INVARIANT (home_holons §5) — a home holon's self-committed `homeName` MUST be the hash of its
91
+ * owner: `homeName == home-<sha256(principal)>`. Declared by the home law, it EXECUTES at the one gate — and
92
+ * crucially at `verify_chain` (the bailiff's upload-birth): a squatter's chain (claiming `home-<hash(bob)>`
93
+ * but owned by `mallory`) FAILS the home law's OWN gate during adoption — refused IN THE GITHOLON, BY THE LAW,
94
+ * never by a host check. The host only routes the chain to the name it commits to (custody). `nomos.sha256`
95
+ * re-derives the hash in-law on every peer, so the verdict is identical everywhere.
96
+ */
97
+ export const homeNameBindsOwner = workspaceInvariant("HomeNameBindsOwner")
98
+ .on("seedHomeOwner")
99
+ .reads(() => [refAs("owner", "HomeOwner", HOME_OWNER_ID)])
100
+ .assert(({ owner }) => {
101
+ const o = (owner ?? {}) as { principal?: string; homeName?: string };
102
+ const expected = HOME_NAME_PREFIX + nomos.sha256(String(o.principal ?? "")).slice(0, HOME_NAME_HASH_LEN);
103
+ return o.homeName === expected
104
+ ? { accept: true }
105
+ : { reject: "a home's name must hash its owner (home-<sha256(principal)>) — refusing a squatted home" };
106
+ });
107
+
74
108
  /**
75
109
  * THE SHARED-WITH-ME INDEX (§5) — one record per cross-custody attestation delivered to this home holon:
76
110
  * a signed edge `<asserterWorkspace> : <object> # <relation> @ this-identity`, indexed LOCALLY so the
package/src/index.ts CHANGED
@@ -243,8 +243,11 @@ export {
243
243
  sharedByWorkspace,
244
244
  HomeOwner,
245
245
  HOME_OWNER_ID,
246
+ HOME_NAME_PREFIX,
247
+ HOME_NAME_HASH_LEN,
246
248
  seedHomeOwner,
247
249
  writeHomeOwner,
250
+ homeNameBindsOwner,
248
251
  } from "./framework/home.js";
249
252
  // THE GENESIS WARRANT (identity_keys.md step 0) — the in-history birth fact that lets
250
253
  // the gate's genesis clause admit a founding control-plane grant on a virgin chain.