@githolon/dsl 0.100.6 → 0.101.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.
Files changed (82) hide show
  1. package/dart/CHANGELOG.md +6 -0
  2. package/dart/lib/src/dev_cloud.dart +46 -15
  3. package/dart/lib/src/test_harness.dart +78 -16
  4. package/dart/lib/src/webview_bridge.dart +640 -126
  5. package/dart/pubspec.lock +1 -1
  6. package/dart/pubspec.yaml +2 -2
  7. package/dart/test/bundle_version_pairing_test.dart +11 -22
  8. package/dart/test/co2_product_gauntlet_test.dart +228 -0
  9. package/dart/test/errors_test.dart +63 -12
  10. package/dart/test/first_app_gauntlet_test.dart +29 -3
  11. package/dart/test/webview_bridge_test.dart +274 -0
  12. package/dart_types/CHANGELOG.md +6 -0
  13. package/dart_types/lib/src/errors.dart +136 -30
  14. package/dart_types/lib/src/surfaced.dart +48 -2
  15. package/dart_types/lib/src/wire.dart +3 -1
  16. package/dart_types/pubspec.yaml +1 -1
  17. package/dart_types/test/surfaced_test.dart +19 -0
  18. package/package.json +1 -1
  19. package/src/activity.ts +43 -4
  20. package/src/aggregate.ts +132 -22
  21. package/src/attested_core.ts +1 -1
  22. package/src/authoring.ts +119 -6
  23. package/src/birth_meter.ts +4 -4
  24. package/src/birth_meter_ensure.ts +9 -1
  25. package/src/births.ts +53 -22
  26. package/src/build_package.ts +55 -14
  27. package/src/business_birth.ts +48 -7
  28. package/src/codegen_dart.ts +267 -37
  29. package/src/codegen_dart_client.ts +921 -82
  30. package/src/codegen_openapi.ts +28 -5
  31. package/src/codegen_proof.ts +107 -11
  32. package/src/codegen_ts.ts +961 -135
  33. package/src/compile_package_main.ts +155 -45
  34. package/src/conflicts.ts +252 -0
  35. package/src/describe_model.ts +448 -0
  36. package/src/directive.ts +5 -38
  37. package/src/drivers.ts +12 -4
  38. package/src/engine_entry.ts +4 -0
  39. package/src/evolve_preview.ts +72 -11
  40. package/src/fields.ts +201 -55
  41. package/src/framework/application_home.ts +103 -0
  42. package/src/framework/application_home_domain.ts +2 -0
  43. package/src/framework/attested_receipts.ts +2 -2
  44. package/src/framework/auth_provider_law.ts +51 -24
  45. package/src/framework/business_corrections.ts +170 -0
  46. package/src/framework/disclosure.ts +1 -1
  47. package/src/framework/domain_lifecycle.ts +250 -16
  48. package/src/framework/encryption_identity.ts +1 -1
  49. package/src/framework/encryption_scope.ts +21 -13
  50. package/src/framework/era_certification.ts +1 -1
  51. package/src/framework/framework_aggregates.ts +2 -0
  52. package/src/framework/genesis.ts +1 -1
  53. package/src/framework/home.ts +22 -9
  54. package/src/framework/identity.ts +5 -5
  55. package/src/framework/impure_capability.ts +2 -2
  56. package/src/framework/owned_custody.ts +561 -0
  57. package/src/framework/platform_admin.ts +1 -1
  58. package/src/framework/relations.ts +9 -1
  59. package/src/framework/repair.ts +1 -1
  60. package/src/framework/signing_identity.ts +2 -2
  61. package/src/framework/source_roster.ts +1 -1
  62. package/src/framework/workspaces.ts +17 -10
  63. package/src/generated_client_names.ts +39 -0
  64. package/src/index.ts +20 -15
  65. package/src/kernel_capabilities.ts +25 -1
  66. package/src/law_check.ts +4 -1
  67. package/src/manifest.ts +356 -63
  68. package/src/read_projection_manifest.ts +8 -0
  69. package/src/read_projection_namespace.ts +4 -0
  70. package/src/relation.ts +1 -1
  71. package/src/shape_compat.ts +47 -2
  72. package/src/stable_ids.ts +38 -6
  73. package/src/stable_ids_types.ts +30 -0
  74. package/src/surfaced_lint.ts +0 -0
  75. package/src/usd.ts +62 -11
  76. package/src/usd_layers.ts +54 -3
  77. package/src/value_object.ts +23 -19
  78. package/src/wire.ts +1 -0
  79. package/src/wire_encode.ts +48 -4
  80. package/src/workspace_routing.ts +57 -0
  81. package/src/workspace_sharding.ts +9 -9
  82. package/src/certified_read.ts +0 -313
@@ -50,6 +50,9 @@ import type { DerivedDecl } from "./derived.js";
50
50
  import type { CombinedDecl } from "./combined.js";
51
51
  import { emitProviderSdk, type ImpureCapabilityDecl } from "./codegen_provider_dart.js";
52
52
  import type { WorkspaceTypeDecl } from "./workspace_type.js";
53
+ import { defaultActivityDescriptor } from "./activity.js";
54
+ import { activityKey } from "./activity.js";
55
+ import { BUSINESS_CORRECTION_DIRECTIVE } from "./framework/business_corrections.js";
53
56
 
54
57
  /** A directive of any payload type. `Directive<P>` is invariant in `P`, so the
55
58
  * generator (which only introspects shapes) takes the `any`-payload form. */
@@ -873,9 +876,11 @@ function aggregateFieldSpecs(
873
876
  ownIdFields: ReadonlySet<string> = new Set(),
874
877
  ): AggFieldSpec[] {
875
878
  const used = new Set<string>(["aggregateId"]);
879
+ const internal = new Set(agg.internalFields ?? []);
876
880
  // `agg.fields` is STORED fields only — virtual `t.hasMany` inverses are in `agg.hasMany`
877
881
  // and never reach Dart materialization (they are served by the inverse read index).
878
882
  return Object.entries(agg.fields as Record<string, Field>)
883
+ .filter(([name]) => !internal.has(name))
879
884
  .map(([name, f]) => {
880
885
  const valueClass =
881
886
  f.kind === "string" && ownIdFields.has(name)
@@ -1315,7 +1320,7 @@ function emitAggregate(
1315
1320
  ...specs.flatMap((s) => {
1316
1321
  const doc = s.nullReason !== undefined ? [` /// null semantic: ${s.nullReason}`] : [];
1317
1322
  // SURFACED MERGE CONFLICTS: the field reads as the plain scalar, or [SurfacedPending]
1318
- // while genuinely concurrent writes await a human pick (resolve = an ordinary next write).
1323
+ // while genuinely concurrent writes await a business merge (resolve = an ordinary next write).
1319
1324
  if (s.surfaced === true) {
1320
1325
  return [
1321
1326
  ` /// Surfaced merge conflicts: [SurfacedResolved] steady state, [SurfacedPending] under conflict.`,
@@ -1914,7 +1919,10 @@ function emitAggregateMetaRegistry(
1914
1919
  if (aggregates.length === 0) return "";
1915
1920
  const entries = aggregates.map((agg) => {
1916
1921
  const wireType = `${domainKey}.${agg.id}`;
1917
- const fieldLines = Object.entries(agg.fields as Record<string, Field>).map(([name, f]) => {
1922
+ const internal = new Set(agg.internalFields ?? []);
1923
+ const fieldLines = Object.entries(agg.fields as Record<string, Field>)
1924
+ .filter(([name]) => !internal.has(name))
1925
+ .map(([name, f]) => {
1918
1926
  const parts: string[] = [`kind: '${f.kind}'`];
1919
1927
  if (f.kind === "enum") {
1920
1928
  try {
@@ -1932,8 +1940,8 @@ function emitAggregateMetaRegistry(
1932
1940
  parts.push(`refType: '${domainKey}.${refTarget}'`);
1933
1941
  }
1934
1942
  if ((f as { isFromBirth?: true }).isFromBirth === true) parts.push(`fromBirth: true`);
1935
- return ` '${name}': NomosFieldMeta(${parts.join(", ")}),`;
1936
- });
1943
+ return ` '${name}': NomosFieldMeta(${parts.join(", ")}),`;
1944
+ });
1937
1945
  return [
1938
1946
  ` '${wireType}': NomosAggregateMeta(`,
1939
1947
  ` type: '${wireType}',`,
@@ -2184,27 +2192,88 @@ export function generateDartContracts(
2184
2192
 
2185
2193
  // ── ACTIVITY DESCRIPTORS (architecture/activity_descriptors.md) — shared registry codegen ──
2186
2194
 
2187
- /** One directive's declared activity, tagged with its provenance (domain + directive id). */
2195
+ /** One public business directive's activity, tagged with its provenance (domain + directive id). */
2188
2196
  export interface PackageActivityEntry {
2189
2197
  readonly domain: string;
2190
2198
  readonly directiveId: string;
2191
2199
  readonly desc: import("./activity.js").ActivityDescriptor;
2200
+ /** False when Nomos supplied the accountable baseline because the tenant declared no richer prose. */
2201
+ readonly declared: boolean;
2202
+ /** Framework-authored testimony whose refs are derived from the corrected action's sealed events. */
2203
+ readonly correction?: true;
2192
2204
  }
2193
2205
 
2194
- /** Collect every directive's `.activity(...)` descriptor across the package's modules, tagged with its
2195
- * domain + directive id, sorted by directive id (byte-deterministic switch/registry order). Empty when
2196
- * no directive opts in — an activity-free package then emits NO registry (byte-identical). Shared by the
2197
- * flat + layered Dart emit AND the TS client (one source of truth). */
2206
+ /**
2207
+ * Collect every PUBLIC business directive across the package. A declared `.activity(...)` descriptor wins;
2208
+ * otherwise Nomos derives a conservative baseline from the verb name + declared output types. This makes
2209
+ * accountability framework-owned: forgetting presentation metadata can make the story less polished, never
2210
+ * incomplete. Framework-private directives remain absent from the application story.
2211
+ */
2198
2212
  export function collectActivityDescriptors(modules: readonly DomainModule[]): PackageActivityEntry[] {
2199
2213
  const out: PackageActivityEntry[] = [];
2200
2214
  for (const mod of modules) {
2201
2215
  const domain = mod.domain ?? mod.name;
2202
2216
  for (const d of mod.directives as AnyDirective[]) {
2217
+ if ((d as { businessBirthInternal?: unknown }).businessBirthInternal === true) {
2218
+ if (d.id === BUSINESS_CORRECTION_DIRECTIVE) {
2219
+ const kind = `${domain}.correction`;
2220
+ out.push({
2221
+ domain,
2222
+ directiveId: d.id,
2223
+ desc: {
2224
+ kind,
2225
+ title: "Correction recorded",
2226
+ message: "{actor} recorded {operation}: {reason}",
2227
+ category: domain,
2228
+ severity: "warning",
2229
+ refs: [],
2230
+ params: [
2231
+ { name: "operation", from: "kind" },
2232
+ { name: "reason", from: "reason" },
2233
+ ],
2234
+ titleKey: activityKey(kind, "title"),
2235
+ messageKey: activityKey(kind, "message"),
2236
+ },
2237
+ declared: false,
2238
+ correction: true,
2239
+ });
2240
+ }
2241
+ continue;
2242
+ }
2203
2243
  const desc = (d as { activityDescriptor?: import("./activity.js").ActivityDescriptor }).activityDescriptor;
2204
- if (desc !== undefined) out.push({ domain, directiveId: d.id, desc });
2244
+ const outputs = [
2245
+ { marker: d.marker, aggregateId: d.aggregateId },
2246
+ ...(d.secondaryOutputs ?? []),
2247
+ ];
2248
+ const seen = new Set<string>();
2249
+ const refs: Array<{ name: string; type: string; from: string }> = [];
2250
+ for (const output of outputs) {
2251
+ const key = `${output.marker}:${output.aggregateId}`;
2252
+ if (seen.has(key)) continue;
2253
+ seen.add(key);
2254
+ refs.push({
2255
+ name: refs.length === 0 ? "subject" : `subject${refs.length + 1}`,
2256
+ type: output.aggregateId,
2257
+ from: output.marker === "creates" ? "@created" : "@affected",
2258
+ });
2259
+ }
2260
+ out.push({
2261
+ domain,
2262
+ directiveId: d.id,
2263
+ desc: desc ?? defaultActivityDescriptor({
2264
+ domain,
2265
+ directiveId: d.id,
2266
+ ...(d.description === undefined ? {} : { description: d.description }),
2267
+ refs,
2268
+ }),
2269
+ declared: desc !== undefined,
2270
+ });
2205
2271
  }
2206
2272
  }
2207
- return out.sort((a, b) => (a.directiveId < b.directiveId ? -1 : a.directiveId > b.directiveId ? 1 : 0));
2273
+ return out.sort((a, b) =>
2274
+ a.domain < b.domain ? -1 : a.domain > b.domain ? 1
2275
+ : a.directiveId < b.directiveId ? -1 : a.directiveId > b.directiveId ? 1 : 0
2276
+ );
2208
2277
  }
2209
2278
 
2210
2279
  /** Dart string literal (single-quoted, backslash/quote/`$` escaped). */
@@ -2212,25 +2281,32 @@ const dartLit = (s: string): string => `'${s.replace(/\\/g, "\\\\").replace(/'/g
2212
2281
 
2213
2282
  /** Emit ONE `case '<directiveId>':` arm folding a raw row into a typed [ActivityEvent]. */
2214
2283
  function emitDartActivityArm(e: PackageActivityEntry): string[] {
2215
- const { directiveId, desc } = e;
2284
+ const { domain, directiveId, desc } = e;
2216
2285
  const paramEntries = desc.params.map((p) => ` ${dartLit(p.name)}: _activityPayloadPath(payload, ${dartLit(p.from)}),`);
2217
- const refEntries = desc.refs.map((r) => {
2286
+ const refEntries = e.correction === true
2287
+ ? [
2288
+ ` for (var i = 0; i < affected.length; i++)`,
2289
+ ` 'subject\${i + 1}': ActivityRef(workspace: workspace, type: (affected[i]['type'] ?? '') as String, id: (affected[i]['id'] ?? '') as String),`,
2290
+ ]
2291
+ : desc.refs.map((r) => {
2218
2292
  // A `from: "@created"` ref reads the id the LAW MINTED (the row's `created` list, first type match); any
2219
2293
  // other `from` is a payload path. Every ref carries the session workspace (the row's `workspace`).
2220
2294
  const id = r.from === "@created"
2221
- ? `_activityCreatedId(created, ${dartLit(r.type)})`
2222
- : `_activityPayloadPath(payload, ${dartLit(r.from)})`;
2295
+ ? `_activityAggregateId(created, ${dartLit(r.type)})`
2296
+ : r.from === "@affected"
2297
+ ? `_activityAggregateId(affected, ${dartLit(r.type)})`
2298
+ : `_activityPayloadPath(payload, ${dartLit(r.from)})`;
2223
2299
  return ` ${dartLit(r.name)}: ActivityRef(workspace: workspace, type: ${dartLit(r.type)}, id: ${id}),`;
2224
- });
2300
+ });
2225
2301
  return [
2226
- ` case ${dartLit(directiveId)}:`,
2302
+ ` case ${dartLit(`${domain.length}:${domain}${directiveId}`)}:`,
2227
2303
  ` {`,
2228
2304
  ` final params = <String, String>{`,
2229
2305
  ...paramEntries,
2230
2306
  ` };`,
2231
2307
  ` final vars = <String, String>{'actor': actorSubject, ...params};`,
2232
2308
  ` return ActivityEvent(`,
2233
- ` eventId: (rawRow['intentId'] ?? '') as String,`,
2309
+ ` eventId: ${e.correction === true ? "_activityOpaqueCorrectionId((rawRow['intentId'] ?? '') as String)" : "(rawRow['intentId'] ?? '') as String"},`,
2234
2310
  ` kind: ${dartLit(desc.kind)},`,
2235
2311
  ` actorSubject: actorSubject,`,
2236
2312
  ` occurredAt: (rawRow['occurredAt'] ?? '') as String,`,
@@ -2246,7 +2322,7 @@ function emitDartActivityArm(e: PackageActivityEntry): string[] {
2246
2322
  ...(desc.icon !== undefined ? [` icon: ${dartLit(desc.icon)},`] : []),
2247
2323
  ` severity: ActivitySeverity.${desc.severity},`,
2248
2324
  ` domain: (rawRow['domain'] ?? '') as String,`,
2249
- ` directiveId: ${dartLit(directiveId)},`,
2325
+ ` directiveId: ${dartLit(e.correction === true ? "correction" : directiveId)},`,
2250
2326
  ` );`,
2251
2327
  ` }`,
2252
2328
  ];
@@ -2258,29 +2334,168 @@ function emitDartActivityArm(e: PackageActivityEntry): string[] {
2258
2334
  * flat + layered emit). References only nomos_types (`ActivityEvent`/`ActivityRef`/`ActivitySeverity`/
2259
2335
  * `renderActivityTemplate`), so the file is PURE (frontend-safe, no bridge). A raw row is
2260
2336
  * `{ intentId, domain, directiveId, actorSubject, occurredAt, payload }` (the runtime's per-committed-intent
2261
- * shape); `renderActivity` returns null for a directive with no declared `.activity(...)`.
2337
+ * shape); `renderActivity` returns null only for work outside the generated public business package.
2262
2338
  */
2263
2339
  export function generateDartActivityRegistry(entries: readonly PackageActivityEntry[]): string {
2264
- const sorted = [...entries].sort((a, b) => (a.directiveId < b.directiveId ? -1 : a.directiveId > b.directiveId ? 1 : 0));
2340
+ const sorted = [...entries].sort((a, b) =>
2341
+ a.domain < b.domain ? -1 : a.domain > b.domain ? 1
2342
+ : a.directiveId < b.directiveId ? -1 : a.directiveId > b.directiveId ? 1 : 0
2343
+ );
2265
2344
  return [
2266
2345
  `// GENERATED by nomos-compile — the package's shared ACTIVITY REGISTRY (architecture/activity_descriptors.md). DO NOT EDIT.`,
2267
- `// A directive OPT-IN declares its user-facing activity metadata; \`renderActivity\` folds each committed-intent`,
2346
+ `// Every public business directive has an accountable baseline row; optional \`.activity(...)\` metadata`,
2347
+ `// enriches its prose and references. \`renderActivity\` folds each committed-intent`,
2268
2348
  `// raw row into a typed ActivityEvent. Pure (nomos_types only) — the kernel/ledger stays the audit truth.`,
2269
2349
  `//`,
2270
- `// ignore_for_file: unused_import`,
2350
+ `// Some baseline-only registries need neither payload interpolation nor one of the aggregate lists.`,
2351
+ `// Keep generated packages analyzer-clean without branching the shared renderer shape per directive mix.`,
2352
+ `// ignore_for_file: unused_import, unused_element, unused_local_variable`,
2271
2353
  `library;`,
2272
2354
  ``,
2273
2355
  `import 'package:nomos_client/nomos_client.dart';`,
2274
2356
  ``,
2275
- `/// A NARRATIVE over the activity log (for an in-app LLM): the filtered [events] + a plain-English`,
2276
- `/// [transcript] (ONE LINE PER EVENT, oldest-first, \`"<occurredAt> — <title>: <message>"\`) grounded in`,
2277
- `/// the VERIFIED log, never raw payloads. Produced by the client's \`describe\` / \`describeHistory\`.`,
2357
+ `/// One business-readable difference found while proving a candidate model against history.`,
2358
+ `enum NomosModelDifferenceKind { rules, outcome, evidence }`,
2359
+ ``,
2360
+ `class NomosModelDifference {`,
2361
+ ` final NomosModelDifferenceKind kind;`,
2362
+ ` final String? area;`,
2363
+ ` final String? action;`,
2364
+ ` final String summary;`,
2365
+ ` const NomosModelDifference({required this.kind, this.area, this.action, required this.summary});`,
2366
+ `}`,
2367
+ ``,
2368
+ `class NomosModelReview {`,
2369
+ ` final int checkedActions;`,
2370
+ ` final int candidateActions;`,
2371
+ ` final bool? sameOutcome;`,
2372
+ ` final List<NomosModelDifference> differences;`,
2373
+ ` const NomosModelReview({required this.checkedActions, required this.candidateActions, required this.sameOutcome, required this.differences});`,
2374
+ `}`,
2375
+ ``,
2376
+ `enum NomosModelAdoptionStatus { adopted, needsDecision, blocked }`,
2377
+ ``,
2378
+ `class NomosModelAdoption {`,
2379
+ ` final NomosModelAdoptionStatus status;`,
2380
+ ` final String summary;`,
2381
+ ` final NomosModelReview review;`,
2382
+ ` final Future<NomosModelAdoption> Function(String)? _accept;`,
2383
+ ` const NomosModelAdoption.adopted({required this.summary, required this.review})`,
2384
+ ` : status = NomosModelAdoptionStatus.adopted, _accept = null;`,
2385
+ ` const NomosModelAdoption.blocked({required this.summary, required this.review})`,
2386
+ ` : status = NomosModelAdoptionStatus.blocked, _accept = null;`,
2387
+ ` NomosModelAdoption.needsDecision({required this.summary, required this.review, required Future<NomosModelAdoption> Function(String) accept})`,
2388
+ ` : status = NomosModelAdoptionStatus.needsDecision, _accept = accept;`,
2389
+ ` Future<NomosModelAdoption> accept(String because) {`,
2390
+ ` final reason = because.trim();`,
2391
+ ` final acceptDecision = _accept;`,
2392
+ ` if (status != NomosModelAdoptionStatus.needsDecision || acceptDecision == null) {`,
2393
+ ` throw StateError('This model change is not waiting for a business decision.');`,
2394
+ ` }`,
2395
+ ` if (reason.isEmpty) throw ArgumentError('accept(reason) needs the business reason for changing prior outcomes');`,
2396
+ ` return acceptDecision(reason);`,
2397
+ ` }`,
2398
+ `}`,
2399
+ ``,
2400
+ `enum NomosModelRestorationStatus { restored, needsDecision, blocked }`,
2401
+ ``,
2402
+ `class NomosModelRestoration {`,
2403
+ ` final NomosModelRestorationStatus status;`,
2404
+ ` final String summary;`,
2405
+ ` final NomosModelReview review;`,
2406
+ ` final Future<NomosModelRestoration> Function(String)? _accept;`,
2407
+ ` const NomosModelRestoration.restored({required this.summary, required this.review})`,
2408
+ ` : status = NomosModelRestorationStatus.restored, _accept = null;`,
2409
+ ` const NomosModelRestoration.blocked({required this.summary, required this.review})`,
2410
+ ` : status = NomosModelRestorationStatus.blocked, _accept = null;`,
2411
+ ` NomosModelRestoration.needsDecision({required this.summary, required this.review, required Future<NomosModelRestoration> Function(String) accept})`,
2412
+ ` : status = NomosModelRestorationStatus.needsDecision, _accept = accept;`,
2413
+ ` Future<NomosModelRestoration> accept(String because) {`,
2414
+ ` final reason = because.trim();`,
2415
+ ` final acceptDecision = _accept;`,
2416
+ ` if (status != NomosModelRestorationStatus.needsDecision || acceptDecision == null) {`,
2417
+ ` throw StateError('This model restoration is not waiting for a business decision.');`,
2418
+ ` }`,
2419
+ ` if (reason.isEmpty) throw ArgumentError('accept(reason) needs the business reason for restoring the previous model');`,
2420
+ ` return acceptDecision(reason);`,
2421
+ ` }`,
2422
+ `}`,
2423
+ ``,
2424
+ `/// This generated package's model, bound to one workspace.`,
2425
+ `class NomosModel {`,
2426
+ ` final Future<NomosModelAdoption> Function() _adopt;`,
2427
+ ` final Future<NomosModelRestoration> Function() _restorePrevious;`,
2428
+ ` const NomosModel(Future<NomosModelAdoption> Function() adopt, Future<NomosModelRestoration> Function() restorePrevious)`,
2429
+ ` : _adopt = adopt, _restorePrevious = restorePrevious;`,
2430
+ ` Future<NomosModelAdoption> adopt() => _adopt();`,
2431
+ ` Future<NomosModelRestoration> restorePrevious() => _restorePrevious();`,
2432
+ `}`,
2433
+ ``,
2434
+ `/// A verified narrative over the activity log. \`describeHistory\` returns this narrow form;`,
2435
+ `/// \`describe\` returns the richer linked [NomosDescription] while preserving these two fields.`,
2278
2436
  `class ActivityNarrative {`,
2279
2437
  ` final List<ActivityEvent> events;`,
2280
2438
  ` final String transcript;`,
2281
2439
  ` const ActivityNarrative({required this.events, required this.transcript});`,
2282
2440
  `}`,
2283
2441
  ``,
2442
+ `/// The root page plus the six product questions every generated client can answer.`,
2443
+ `enum NomosDescribeSection { root, model, current, rules, history, decisions, evidence }`,
2444
+ ``,
2445
+ `class NomosDescribeLink {`,
2446
+ ` final NomosDescribeSection section;`,
2447
+ ` final String label;`,
2448
+ ` final String question;`,
2449
+ ` final String summary;`,
2450
+ ` const NomosDescribeLink({required this.section, required this.label, required this.question, required this.summary});`,
2451
+ `}`,
2452
+ ``,
2453
+ `class NomosDescribeItem {`,
2454
+ ` final String kind;`,
2455
+ ` final String id;`,
2456
+ ` final String label;`,
2457
+ ` final String summary;`,
2458
+ ` final Map<String, dynamic>? details;`,
2459
+ ` final List<NomosRef> refs;`,
2460
+ ` const NomosDescribeItem({required this.kind, required this.id, required this.label, required this.summary, this.details, this.refs = const []});`,
2461
+ `}`,
2462
+ ``,
2463
+ `/// A parent-ledger link to another part of the organisation. Open that workspace's generated client`,
2464
+ `/// and call describe() again; each child explains itself in its own installed business language.`,
2465
+ `class NomosDescribeChild {`,
2466
+ ` final String workspace;`,
2467
+ ` final String status;`,
2468
+ ` final String? bornAt;`,
2469
+ ` final NomosDescribeSection section;`,
2470
+ ` final String label;`,
2471
+ ` final String question;`,
2472
+ ` final String summary;`,
2473
+ ` const NomosDescribeChild({`,
2474
+ ` required this.workspace, required this.status, required this.bornAt,`,
2475
+ ` this.section = NomosDescribeSection.root, required this.label, required this.question, required this.summary,`,
2476
+ ` });`,
2477
+ `}`,
2478
+ ``,
2479
+ `class NomosOrganisationDescription {`,
2480
+ ` final bool complete;`,
2481
+ ` final List<NomosDescribeChild> children;`,
2482
+ ` const NomosOrganisationDescription({required this.complete, required this.children});`,
2483
+ `}`,
2484
+ ``,
2485
+ `/// One grounded page in the hierarchical self-description. Root links to exactly six detail pages.`,
2486
+ `class NomosDescription extends ActivityNarrative {`,
2487
+ ` final NomosDescribeSection section;`,
2488
+ ` final String title;`,
2489
+ ` final String summary;`,
2490
+ ` final List<NomosDescribeItem> items;`,
2491
+ ` final List<NomosDescribeLink> links;`,
2492
+ ` final NomosOrganisationDescription organisation;`,
2493
+ ` const NomosDescription({`,
2494
+ ` required this.section, required this.title, required this.summary, required this.items,`,
2495
+ ` required this.links, required this.organisation, required super.events, required super.transcript,`,
2496
+ ` });`,
2497
+ `}`,
2498
+ ``,
2284
2499
  `/// Wrap events into an [ActivityNarrative], building the LLM-ready transcript: one line per event,`,
2285
2500
  `/// OLDEST-FIRST (the log yields newest-first).`,
2286
2501
  `ActivityNarrative activityNarrative(List<ActivityEvent> events) => ActivityNarrative(`,
@@ -2298,29 +2513,42 @@ export function generateDartActivityRegistry(entries: readonly PackageActivityEn
2298
2513
  ` return cur == null ? '' : '\$cur';`,
2299
2514
  `}`,
2300
2515
  ``,
2301
- `/// The id the LAW minted for a \`from: "@created"\` ref — the first entry of the row's \`created\` list`,
2302
- `/// whose type matches the declared aggregate (the runtime type is uuid-stripped + may be namespaced, so`,
2303
- `/// match on equality OR \`<domain>.<Type>\` suffix). '' when the holon returned no created list (era-safe).`,
2304
- `String _activityCreatedId(List<Map<String, dynamic>> created, String declared) {`,
2305
- ` for (final c in created) {`,
2516
+ `/// Resolve the first aggregate of a declared type from either the row's minted \`created\` refs or its`,
2517
+ `/// complete touched \`affected\` refs (used by framework-owned baseline stories).`,
2518
+ `String _activityAggregateId(List<Map<String, dynamic>> aggregates, String declared) {`,
2519
+ ` for (final c in aggregates) {`,
2306
2520
  ` final t = (c['type'] ?? '') as String;`,
2307
2521
  ` if (t == declared || t.endsWith('.\$declared')) return (c['id'] ?? '') as String;`,
2308
2522
  ` }`,
2309
2523
  ` return '';`,
2310
2524
  `}`,
2311
2525
  ``,
2312
- `/// Fold ONE committed-intent raw row into a typed [ActivityEvent], or null when the directive declares`,
2313
- `/// no \`.activity(...)\`. rawRow = { intentId, domain, directiveId, actorSubject, occurredAt, payload,`,
2314
- `/// created, workspace } — \`created\` (\`[{type,id}]\`) backs \`from: "@created"\` refs; \`workspace\` stamps them.`,
2526
+ `/// Keep a framework-private correction identity stable and traceable without exposing its internal name.`,
2527
+ `String _activityOpaqueCorrectionId(String id) {`,
2528
+ ` String hash(int seed) {`,
2529
+ ` var h = seed & 0xffffffff;`,
2530
+ ` for (final code in id.codeUnits) h = ((h ^ code) * 16777619) & 0xffffffff;`,
2531
+ ` return h.toRadixString(16).padLeft(8, '0');`,
2532
+ ` }`,
2533
+ ` return 'correction-\${hash(2166136261)}\${hash(2246822507)}';`,
2534
+ `}`,
2535
+ ``,
2536
+ `/// Fold ONE committed-intent raw row into a typed [ActivityEvent], or null for framework/control work`,
2537
+ `/// outside this generated business package. rawRow carries both minted \`created\` and all touched`,
2538
+ `/// \`affected\` aggregate refs; \`workspace\` stamps them.`,
2315
2539
  `ActivityEvent? renderActivity(Map<String, dynamic> rawRow) {`,
2316
2540
  ` final directiveId = (rawRow['directiveId'] ?? '') as String;`,
2317
2541
  ` final actorSubject = (rawRow['actorSubject'] ?? '') as String;`,
2542
+ ` final domain = (rawRow['domain'] ?? '') as String;`,
2318
2543
  ` final workspace = (rawRow['workspace'] ?? '') as String;`,
2319
2544
  ` final payload = ((rawRow['payload'] as Map?)?.cast<String, dynamic>()) ?? const <String, dynamic>{};`,
2320
2545
  ` final created = ((rawRow['created'] as List?) ?? const <dynamic>[])`,
2321
2546
  ` .map((e) => (e as Map).cast<String, dynamic>())`,
2322
2547
  ` .toList();`,
2323
- ` switch (directiveId) {`,
2548
+ ` final affected = ((rawRow['affected'] as List?) ?? const <dynamic>[])`,
2549
+ ` .map((e) => (e as Map).cast<String, dynamic>())`,
2550
+ ` .toList();`,
2551
+ ` switch ('${'$'}{domain.length}:${'$'}domain${'$'}directiveId') {`,
2324
2552
  ...sorted.flatMap(emitDartActivityArm),
2325
2553
  ` default:`,
2326
2554
  ` return null;`,
@@ -3969,8 +4197,10 @@ export interface DomainModule {
3969
4197
  /**
3970
4198
  * THE DESIGNATED SURFACED RESOLVERS (surfaced_lint.ts) — one binding per `.merge(Surfaced(...))`
3971
4199
  * field, produced (and fail-closed enforced: exactly one `.resolves()` per Surfaced field, every
3972
- * Surfaced field covered) by `composeDomainModule`. Drives the generated typed `resolve…` helpers
3973
- * (TS + Dart) and the `pendingConflicts` accessor. NOT law, NOT hashed (like {@link roles}).
4200
+ * Surfaced field covered) by `composeDomainModule`. Drives the generated typed conflict references
4201
+ * (TS + Dart), the `pendingConflicts` accessor, and the manifest's hash-bearing
4202
+ * `conflictResolution` declaration. The traced payload-field names remain codegen metadata;
4203
+ * the aggregate/field/directive binding is law.
3974
4204
  * Absent when the domain declares no Surfaced field (byte-identical — the era rule).
3975
4205
  */
3976
4206
  surfacedResolvers?: import("./surfaced_lint.js").SurfacedResolverBinding[];