@rubytech/create-sitedesk-code 0.1.495 → 0.1.496

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 (67) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/insight/SKILL.md +1 -1
  3. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +17 -6
  4. package/payload/platform/plugins/docs/references/admin-ui.md +16 -5
  5. package/payload/platform/plugins/memory/references/schema-estate-agent.md +1 -1
  6. package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +51 -7
  7. package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +4 -1
  8. package/payload/platform/scripts/lib/account-schema-owned-dirs.py +13 -1
  9. package/payload/platform/scripts/lib/account-schema-owned-dirs.sh +23 -1
  10. package/payload/platform/scripts/lib/provision-account-dir.sh +5 -0
  11. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.d.ts +15 -0
  12. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.d.ts.map +1 -1
  13. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.js +19 -0
  14. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.js.map +1 -1
  15. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts +1 -1
  16. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts.map +1 -1
  17. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js +16 -3
  18. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js.map +1 -1
  19. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/gates.test.ts +25 -0
  20. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/render-run.test.ts +52 -0
  21. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/gates.ts +19 -0
  22. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/render-run.ts +16 -3
  23. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-generation.md +14 -5
  24. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/verification.md +9 -4
  25. package/payload/server/public/activity.html +5 -5
  26. package/payload/server/public/assets/{AdminLoginScreens-DgVFsHtd.js → AdminLoginScreens-CFF28MGy.js} +1 -1
  27. package/payload/server/public/assets/AdminShell-ClIT8c0K.js +2 -0
  28. package/payload/server/public/assets/{activity-2DL2DwLr.js → activity-CElZcdjR.js} +1 -1
  29. package/payload/server/public/assets/{admin-COe0dT2U.js → admin-BHiA9_Ks.js} +1 -1
  30. package/payload/server/public/assets/{bot-CpBuDQlF.js → bot-Q-JmeVT3.js} +1 -1
  31. package/payload/server/public/assets/{browser-CSApuZrv.js → browser-BrfPJMYF.js} +1 -1
  32. package/payload/server/public/assets/{calendar-DlvwZnS7.js → calendar-D45S_aal.js} +1 -1
  33. package/payload/server/public/assets/chat-gy8scQov.js +1 -0
  34. package/payload/server/public/assets/chevron-down-CdxvexgY.js +1 -0
  35. package/payload/server/public/assets/chevron-left-D5LLz6ke.js +1 -0
  36. package/payload/server/public/assets/chevron-right-DzPmwDew.js +1 -0
  37. package/payload/server/public/assets/data-CUsNHUpu.js +1 -0
  38. package/payload/server/public/assets/{graph-kaxS9a_7.js → graph-BLO4nVi3.js} +1 -1
  39. package/payload/server/public/assets/{graph-labels-GgejRtgV.js → graph-labels-ibEi7ggo.js} +1 -1
  40. package/payload/server/public/assets/{maximize-2-CPq3nwZA.js → maximize-2-CezchDEF.js} +1 -1
  41. package/payload/server/public/assets/{operator-Cxq9TxaH.js → operator-B-3vkwO8.js} +1 -1
  42. package/payload/server/public/assets/{page-DBHzC59_.js → page-BL1ko2_-.js} +1 -1
  43. package/payload/server/public/assets/{page-BE6DkJP9.js → page-BbxoY4QI.js} +1 -1
  44. package/payload/server/public/assets/{public-jIzvdjt_.js → public-DxfSLhNp.js} +1 -1
  45. package/payload/server/public/assets/{rotate-ccw-DieZzl10.js → rotate-ccw-CWvGAut4.js} +1 -1
  46. package/payload/server/public/assets/{tasks-DYyCGz8W.js → tasks-DlXIN3v3.js} +1 -1
  47. package/payload/server/public/assets/{time-entry-format-CC_9jFuR.js → time-entry-format-VzHwljTv.js} +1 -1
  48. package/payload/server/public/assets/{triangle-alert-7mQfCQWP.js → triangle-alert-C5BpoPlq.js} +1 -1
  49. package/payload/server/public/assets/{useCopyFeedback-os7N0yCx.js → useCopyFeedback-h1qT8mpZ.js} +1 -1
  50. package/payload/server/public/assets/{useSubAccountSwitcher-Bgfqig1V.css → useSubAccountSwitcher-DnfX9Uxe.css} +1 -1
  51. package/payload/server/public/assets/{useVoiceRecorder-ZFwt5i6d.js → useVoiceRecorder-kqMitFlk.js} +1 -1
  52. package/payload/server/public/browser.html +4 -4
  53. package/payload/server/public/calendar.html +6 -6
  54. package/payload/server/public/chat.html +13 -13
  55. package/payload/server/public/data.html +10 -10
  56. package/payload/server/public/graph.html +10 -10
  57. package/payload/server/public/index.html +15 -15
  58. package/payload/server/public/operator.html +14 -14
  59. package/payload/server/public/public.html +13 -13
  60. package/payload/server/public/tasks.html +6 -6
  61. package/payload/server/public/assets/AdminShell-BwNqwb4k.js +0 -2
  62. package/payload/server/public/assets/chat-1SSmFsjd.js +0 -1
  63. package/payload/server/public/assets/chevron-down-Dnuuw6Q2.js +0 -1
  64. package/payload/server/public/assets/chevron-left-CC4zmWOr.js +0 -1
  65. package/payload/server/public/assets/chevron-right-CG_lHTx_.js +0 -1
  66. package/payload/server/public/assets/data-CJbC_cVy.js +0 -1
  67. /package/payload/server/public/assets/{useSubAccountSwitcher-Q941cZYV.js → useSubAccountSwitcher-DDStL7Nt.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-sitedesk-code",
3
- "version": "0.1.495",
3
+ "version": "0.1.496",
4
4
  "description": "Install SiteDesk — automated back office for independent building contractors",
5
5
  "bin": {
6
6
  "create-sitedesk-code": "./dist/index.js"
@@ -15,7 +15,7 @@ Run the four passes now over the session so far, then keep going in this same se
15
15
 
16
16
  Pass 1 — Technical learnings. Walk this session for operator corrections and self-detected mistakes. For each one, delegate one graph write to `database-operator` via the Task tool, persisting a Learning or Correction node per the schema. Count what you write.
17
17
 
18
- Pass 2 — Operator-relationship updates. Walk this session for tonal signals, rejected phrasings, and working-style preferences. For each one worth carrying forward, Write the observation into `SOUL.md` at the account-scoped path. Count what you write.
18
+ Pass 2 — Operator-relationship updates. Walk this session for tonal signals, rejected phrasings, and working-style preferences. For each one worth carrying forward, Write the observation into `agents/admin/SOUL.md`, the account-scoped identity path the spawn composer reads. That path is the only identity file; never write a bare `SOUL.md` at the account root, which the composer never reads and the schema guard blocks. Count what you write.
19
19
 
20
20
  Pass 3 — Graph completeness sweep. Walk this session for any node, edge, or commitment that was discussed but not written to the graph in-flight. For each missing write, delegate to `database-operator` via the Task tool. Count what you write.
21
21
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what SiteDesk ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:bf5eeb6446bc1a8e06f0fc7455eaad5ddc460397c58d4dbfb985e18d8e96686d
4
+ content-hash: sha256:e3da93a9c86c4a41c7ea79d4cdc353a85ac8c69826cc5238c9d2c00d53811895
5
5
  brand: sitedesk-code
6
6
  product-name: SiteDesk
7
7
  ---
@@ -3300,9 +3300,11 @@ authoritative. This section names the surfaces and what backs each.
3300
3300
  >
3301
3301
  > - **Nav rows** are Dashboard, Chat, Tasks, Calendar, Data, the brand container
3302
3302
  > row (Projects / Properties / Jobs, opening the graph filtered to the brand's
3303
- > primary container), Activity, and Browser. The active row carries an accent
3304
- > left indicator. The older People / Agents / Artefacts entries in the table
3305
- > below are pre-redesign.
3303
+ > primary container), Graph (the unfiltered whole graph at `/graph`, waypoints
3304
+ > icon active on plain `/graph`; the container row is active only when a
3305
+ > `label=` filter is present), Activity, and Browser. The active row carries an
3306
+ > accent left indicator. The older People / Agents / Artefacts entries in the
3307
+ > table below are pre-redesign.
3306
3308
  > - **Dashboard home** renders on `/` (a greeting, stat cards, a Live-now column,
3307
3309
  > a Recent artefacts card, and a Channels column), consuming existing endpoints
3308
3310
  > only.
@@ -3317,14 +3319,23 @@ authoritative. This section names the surfaces and what backs each.
3317
3319
  > - **Mobile (< 720px).** The sidebar opens as a drawer from a 44x44 header menu
3318
3320
  > button, and a fixed bottom tab bar (Home, Chat, Tasks, Data, Calendar) sits
3319
3321
  > under the content; Graph, Activity, and Browser stay reachable through the
3320
- > drawer. Between 721 and 1080px the sidebar defaults to the rail.
3322
+ > drawer. Between 721 and 1080px the sidebar defaults to the rail. The
3323
+ > drawer's SESSIONS head collapses its New-session pill to an icon-only `+`
3324
+ > (34px square); the label returns above 720px. The **operator** variant gets
3325
+ > its own fixed bottom tab bar — Chat, Conversations (rendered only when the
3326
+ > pane handler is wired), Data — while its burger keeps the AccountMenu tail.
3327
+ > In the webchat composer the icon control bar moves **above** the input box
3328
+ > with 44px touch squares (desktop keeps the below-input row), and the
3329
+ > composer placeholder never wraps (single line, ellipsized).
3321
3330
 
3322
3331
  > **Admin variant only.** Every surface below belongs to the `admin` shell
3323
3332
  > variant. The **operator** variant (`operator.<host>`) mounts no sidebar at
3324
3333
  > all: its dashboard is the persistent admin webchat at `/` and the data
3325
3334
  > browser at `/data`, plus a **Conversations** item reached from a dynamic
3326
3335
  > burger item — header order Chat → Conversations → Data → Log out, in a
3327
- > single-column `.platform.platform-operator` grid. On the operator **chat**
3336
+ > single-column `.platform.platform-operator` grid. Below 720px the same three
3337
+ > nav items also render as the operator bottom tab bar (see Mobile above);
3338
+ > the Chat tab targets the operator root `/`, the canonical-session route. On the operator **chat**
3328
3339
  > surface the Conversations item opens the same in-chat session
3329
3340
  > switcher the admin `/chat` surface uses (`ChatSurface`'s `SessionList` flyout):
3330
3341
  > the operator's own admin webchat conversations, newest-first, each resuming
@@ -399,9 +399,11 @@ authoritative. This section names the surfaces and what backs each.
399
399
  >
400
400
  > - **Nav rows** are Dashboard, Chat, Tasks, Calendar, Data, the brand container
401
401
  > row (Projects / Properties / Jobs, opening the graph filtered to the brand's
402
- > primary container), Activity, and Browser. The active row carries an accent
403
- > left indicator. The older People / Agents / Artefacts entries in the table
404
- > below are pre-redesign.
402
+ > primary container), Graph (the unfiltered whole graph at `/graph`, waypoints
403
+ > icon active on plain `/graph`; the container row is active only when a
404
+ > `label=` filter is present), Activity, and Browser. The active row carries an
405
+ > accent left indicator. The older People / Agents / Artefacts entries in the
406
+ > table below are pre-redesign.
405
407
  > - **Dashboard home** renders on `/` (a greeting, stat cards, a Live-now column,
406
408
  > a Recent artefacts card, and a Channels column), consuming existing endpoints
407
409
  > only.
@@ -416,14 +418,23 @@ authoritative. This section names the surfaces and what backs each.
416
418
  > - **Mobile (< 720px).** The sidebar opens as a drawer from a 44x44 header menu
417
419
  > button, and a fixed bottom tab bar (Home, Chat, Tasks, Data, Calendar) sits
418
420
  > under the content; Graph, Activity, and Browser stay reachable through the
419
- > drawer. Between 721 and 1080px the sidebar defaults to the rail.
421
+ > drawer. Between 721 and 1080px the sidebar defaults to the rail. The
422
+ > drawer's SESSIONS head collapses its New-session pill to an icon-only `+`
423
+ > (34px square); the label returns above 720px. The **operator** variant gets
424
+ > its own fixed bottom tab bar — Chat, Conversations (rendered only when the
425
+ > pane handler is wired), Data — while its burger keeps the AccountMenu tail.
426
+ > In the webchat composer the icon control bar moves **above** the input box
427
+ > with 44px touch squares (desktop keeps the below-input row), and the
428
+ > composer placeholder never wraps (single line, ellipsized).
420
429
 
421
430
  > **Admin variant only.** Every surface below belongs to the `admin` shell
422
431
  > variant. The **operator** variant (`operator.<host>`) mounts no sidebar at
423
432
  > all: its dashboard is the persistent admin webchat at `/` and the data
424
433
  > browser at `/data`, plus a **Conversations** item reached from a dynamic
425
434
  > burger item — header order Chat → Conversations → Data → Log out, in a
426
- > single-column `.platform.platform-operator` grid. On the operator **chat**
435
+ > single-column `.platform.platform-operator` grid. Below 720px the same three
436
+ > nav items also render as the operator bottom tab bar (see Mobile above);
437
+ > the Chat tab targets the operator root `/`, the canonical-session route. On the operator **chat**
427
438
  > surface the Conversations item opens the same in-chat session
428
439
  > switcher the admin `/chat` surface uses (`ChatSurface`'s `SessionList` flyout):
429
440
  > the operator's own admin webchat conversations, newest-first, each resuming
@@ -13,7 +13,7 @@ When loading this reference, confirm: "Using schema-base + schema-estate-agent".
13
13
  | Entity | Neo4j Label | Owner | Schema.org Type | Required Properties |
14
14
  |--------|-------------|-------|-----------------|---------------------|
15
15
  | Property | `Property` | | `schema:Accommodation` | `accountId`, `slug` (id, address-derived), `address` |
16
- | Listing | `Listing` | | `schema:RealEstateListing` | `accountId`, `slug`, `displayName`, `listingType` (sale/let), `status`, `sourceSystem`, `sourceId`, `scope`, `heroImageUrl`*, `pageUrl`*, `blurb` |
16
+ | Listing | `Listing` | `Property` | `schema:RealEstateListing` | `accountId`, `slug`, `displayName`, `listingType` (sale/let), `status`, `sourceSystem`, `sourceId`, `scope`, `heroImageUrl`*, `pageUrl`*, `blurb` |
17
17
  | Viewing | `Viewing` | `Listing` | `schema:Event` (subtype) | `accountId`, `listing` (id), `applicant` (id), `date`, `feedback`, `outcome` |
18
18
  | Offer | `Offer` | `Listing` | `schema:Offer` | `accountId`, `listing` (id), `applicant` (id), `price`, `conditions`, `status`, `date` |
19
19
 
@@ -13,6 +13,8 @@ PASS=0; FAIL=0; FAILED=()
13
13
  assert_grep() { if printf '%s' "$2" | grep -qF "$1"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$3: expected to find [$1]"); fi; }
14
14
  assert_nogrep() { if printf '%s' "$2" | grep -qF "$1"; then FAIL=$((FAIL+1)); FAILED+=("$3: expected NOT to find [$1]"); else PASS=$((PASS+1)); fi; }
15
15
  assert_eq() { if [ "$1" = "$2" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$3: expected [$2] got [$1]"); fi; }
16
+ assert_dir() { if [ -d "$1" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$2: expected directory [$1]"); fi; }
17
+ assert_nodir() { if [ -d "$1" ]; then FAIL=$((FAIL+1)); FAILED+=("$2: expected NO directory [$1]"); else PASS=$((PASS+1)); fi; }
16
18
 
17
19
  . "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.sh"
18
20
 
@@ -156,21 +158,63 @@ assert_eq "$(shasum "$A_C/SCHEMA.md" | awk '{print $1}')" "$B_C" "con-idempotent
156
158
  RCS="$(PROJECT_DIR="$PROJECT_DIR" python3 "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.py" reconcile "$A_C")"
157
159
  assert_grep "ontologyEntity=Supplier bucket=suppliers present=true" "$RCS" "con-supplier-root-present"
158
160
 
159
- # --- estate-agent vertical: root buckets only, listing-owned entities nested ---
161
+ # --- estate-agent vertical: Property is the sole root; Listing (and its own
162
+ # children Viewing/Offer) nest, mirroring Quote<-Job in construction ---
160
163
  T_E="$(make_vertical_tree '["real-agent"]' 'schema-estate-agent')"; A_E="$(make_account "$T_E")"
161
164
  export PROJECT_DIR="$T_E/platform"
162
- merge_owned_dirs_into_schema "$A_E" >/dev/null
165
+ OUT_E="$(merge_owned_dirs_into_schema "$A_E")"
166
+ assert_grep "domainBuckets=properties" "$OUT_E" "ea-domain-log"
167
+ assert_grep "roots=properties" "$OUT_E" "ea-roots-log"
168
+ assert_grep "nested=Listing<-Property,Viewing<-Listing,Offer<-Listing" "$OUT_E" "ea-nested-log"
163
169
  ALLOWED_E="$(awk '/^```allowed-top-level$/{f=1;next} /^```$/{f=0} f' "$A_E/SCHEMA.md")"
164
- # Root entities get a bucket; Listing-owned Viewing/Offer do not.
165
- for d in properties listings; do
166
- assert_grep "$d" "$ALLOWED_E" "ea-allow-$d"
167
- done
168
- for d in viewings offers; do
170
+ # Property (blank Owner) is the only root bucket.
171
+ assert_grep "properties" "$ALLOWED_E" "ea-allow-properties"
172
+ # Listing and its children nest; none is a root bucket.
173
+ for d in listings viewings offers; do
169
174
  assert_nogrep "$d" "$ALLOWED_E" "ea-noroot-$d"
170
175
  done
171
176
  assert_nogrep "jobs" "$ALLOWED_E" "ea-no-sitedesk-jobs"
172
177
  # The suppliers/ bucket is construction-only; it must not leak into another vertical.
173
178
  assert_nogrep "suppliers" "$ALLOWED_E" "ea-no-suppliers"
179
+ # The descriptive region tells the agent Listing records live under properties/.
180
+ assert_grep '`Listing` records live under `properties/` (owned by `Property`), not a root bucket.' "$(cat "$A_E/SCHEMA.md")" "ea-nested-line"
181
+
182
+ # --- roots subcommand + seed_domain_root_dirs: buckets materialise on disk ---
183
+ # estate-agent (PROJECT_DIR still $T_E/platform): properties/ is created.
184
+ ROOTS_E="$(PROJECT_DIR="$T_E/platform" python3 "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.py" roots)"
185
+ assert_grep "properties" "$ROOTS_E" "ea-roots-cmd"
186
+ assert_nogrep "listings" "$ROOTS_E" "ea-roots-cmd-no-listings"
187
+ SEED_E="$(seed_domain_root_dirs "$A_E")"
188
+ assert_grep "seeded-roots=properties" "$SEED_E" "ea-seed-log"
189
+ assert_dir "$A_E/properties" "ea-seed-dir"
190
+ # Idempotent: a second run creates nothing.
191
+ SEED_E2="$(seed_domain_root_dirs "$A_E")"
192
+ assert_grep "seeded-roots=none" "$SEED_E2" "ea-seed-idempotent"
193
+
194
+ # construction: every root bucket is created; nested entities are not.
195
+ export PROJECT_DIR="$T_C/platform"
196
+ A_SEED_C="$(make_account "$T_C")"
197
+ ROOTS_C="$(PROJECT_DIR="$T_C/platform" python3 "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.py" roots)"
198
+ for d in jobs customers customer-sites assets parts suppliers ppm-contracts; do
199
+ assert_grep "$d" "$ROOTS_C" "con-roots-cmd-$d"
200
+ done
201
+ seed_domain_root_dirs "$A_SEED_C" >/dev/null
202
+ for d in jobs customers customer-sites assets parts suppliers ppm-contracts; do
203
+ assert_dir "$A_SEED_C/$d" "con-seed-dir-$d"
204
+ done
205
+ for d in quotes visits purchase-orders; do
206
+ assert_nodir "$A_SEED_C/$d" "con-seed-nonested-$d"
207
+ done
208
+
209
+ # The all-accounts sweep seeds an existing account's root buckets too, so a
210
+ # sub-account (provisioned once at creation) gains properties/ on upgrade.
211
+ export PROJECT_DIR="$T_E/platform"
212
+ SWEEP_ACCTS="$(mktemp -d)"; mkdir -p "$SWEEP_ACCTS/ea1"
213
+ cp "$T_E/platform/templates/account-schema/SCHEMA.md" "$SWEEP_ACCTS/ea1/SCHEMA.md"
214
+ printf '{"accountId":"ea1","role":"client"}\n' > "$SWEEP_ACCTS/ea1/account.json"
215
+ SWEEP_E="$(reconcile_all_accounts_owned_dirs "$SWEEP_ACCTS" 2>&1)"
216
+ assert_grep "seeded-roots=properties" "$SWEEP_E" "sweep-seed-log"
217
+ assert_dir "$SWEEP_ACCTS/ea1/properties" "sweep-seed-properties-dir"
174
218
 
175
219
  # --- no vertical declared: generic base only ---
176
220
  T_N="$(make_tree '[]')"; A_N="$(make_account "$T_N")"
@@ -20,8 +20,11 @@ export USERS_FILE="/nonexistent/users.json"
20
20
 
21
21
  # Fresh account -> role=house stamped
22
22
  T1=$(mktemp -d); A1="$T1/acct-house"
23
- provision_account_dir "$A1" "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" "house" >/dev/null 2>&1
23
+ OUT1="$(provision_account_dir "$A1" "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" "house" 2>/dev/null)"
24
24
  assert_eq "$(role_of "$A1/account.json")" "house" "fresh-house-role"
25
+ # Task 1938 — provision seeds the vertical's root domain buckets; the log line
26
+ # proves seed_domain_root_dirs ran (bucket set depends on the brand's vertical).
27
+ assert_eq "$(printf '%s' "$OUT1" | grep -c 'seeded-roots=')" "1" "fresh-seed-roots-logged"
25
28
  assert_eq "$(ms_of "$A1/account.json")" "False" "fresh-managedService-default"
26
29
  # Task 1483 — the WhatsApp passive requirement-intake identity is seeded, non-empty.
27
30
  assert_nonempty "$A1/agents/passive/IDENTITY.md" "passive-identity-seeded"
@@ -410,9 +410,19 @@ def reconcile(project_dir, account_dir):
410
410
  f"bucket={b['dir']} expectedAtRoot=false stray={is_stray}")
411
411
 
412
412
 
413
+ def roots(project_dir):
414
+ """Print each root domain bucket dir (blank/absent Owner) of the brand's
415
+ vertical, one per line, in table order. Empty when no vertical is declared.
416
+ Provision consumes this to mkdir the operator-data buckets so they exist as
417
+ directories, not just allowed names."""
418
+ for b in resolve_domain_buckets(project_dir):
419
+ if _is_root(b["owner"]):
420
+ print(b["dir"])
421
+
422
+
413
423
  def main():
414
424
  if len(sys.argv) < 2:
415
- sys.exit("usage: account-schema-owned-dirs.py {resolve|merge|reconcile} [account_dir]")
425
+ sys.exit("usage: account-schema-owned-dirs.py {resolve|merge|reconcile|roots} [account_dir]")
416
426
  cmd = sys.argv[1]
417
427
  pd = _project_dir()
418
428
  if cmd == "resolve":
@@ -421,6 +431,8 @@ def main():
421
431
  merge(pd, sys.argv[2])
422
432
  elif cmd == "reconcile":
423
433
  reconcile(pd, sys.argv[2])
434
+ elif cmd == "roots":
435
+ roots(pd)
424
436
  else:
425
437
  sys.exit(f"unknown command: {cmd}")
426
438
 
@@ -17,9 +17,30 @@ merge_owned_dirs_into_schema() {
17
17
  echo " [acct-schema] op=seed-owned-dirs ${_out}"
18
18
  }
19
19
 
20
+ # seed_domain_root_dirs <account_dir>
21
+ # mkdir each root domain bucket the brand's vertical projects (Property ->
22
+ # properties/ for estate-agent, Job/Customer/... for construction), so the
23
+ # operator-data buckets exist as directories, not just allowed names. Idempotent.
24
+ # Logs the buckets created so a provision can be audited from its log.
25
+ seed_domain_root_dirs() {
26
+ local _acct="$1"
27
+ local _created=""
28
+ local _d
29
+ while IFS= read -r _d; do
30
+ [ -n "$_d" ] || continue
31
+ if [ ! -d "$_acct/$_d" ]; then
32
+ mkdir -p "$_acct/$_d"
33
+ _created="${_created:+$_created,}$_d"
34
+ fi
35
+ done < <(PROJECT_DIR="$PROJECT_DIR" python3 "$_ACCT_SCHEMA_PY" roots 2>/dev/null)
36
+ echo " [acct-schema] seeded-roots=${_created:-none}"
37
+ }
38
+
20
39
  # reconcile_all_accounts_owned_dirs <accounts_dir>
21
40
  # Standing check + backfill: for every account dir with an account.json, log the
22
- # pre-merge present state of each declared owned dir, then merge (backfill).
41
+ # pre-merge present state of each declared owned dir, merge (backfill), then seed
42
+ # the vertical's root buckets so an existing account (sub-accounts are only
43
+ # provisioned once, at creation) gains the same directories a fresh one gets.
23
44
  reconcile_all_accounts_owned_dirs() {
24
45
  local _accts="$1"
25
46
  [ -d "$_accts" ] || return 0
@@ -29,5 +50,6 @@ reconcile_all_accounts_owned_dirs() {
29
50
  PROJECT_DIR="$PROJECT_DIR" python3 "$_ACCT_SCHEMA_PY" reconcile "$_acct" 2>/dev/null \
30
51
  | while IFS= read -r _line; do echo " [acct-schema] op=reconcile ${_line}"; done
31
52
  merge_owned_dirs_into_schema "$_acct"
53
+ seed_domain_root_dirs "$_acct"
32
54
  done
33
55
  }
@@ -45,6 +45,11 @@ provision_account_dir() {
45
45
  # seeded SCHEMA.md so the guard admits them (e.g. quoting/ on SiteDesk).
46
46
  merge_owned_dirs_into_schema "$ACCOUNT_DIR"
47
47
 
48
+ # Create the vertical's root domain buckets on disk (Property -> properties/
49
+ # for estate-agent, Job/Customer/... for construction) so they are present
50
+ # directories, not just allowed names the operator never sees.
51
+ seed_domain_root_dirs "$ACCOUNT_DIR"
52
+
48
53
  # Claude Code discovers project-level .claude/ relative to the nearest .git
49
54
  # root. Without a .git in the account dir it traverses up to ~/maxy/.git and
50
55
  # misses accountDir/.claude/. Initialise a repo so the account dir IS the root.
@@ -27,6 +27,11 @@ export interface RefVerdict {
27
27
  reason?: "inconsistent";
28
28
  refs?: string[];
29
29
  }
30
+ export interface SignatureVerdict {
31
+ pass: boolean;
32
+ skipped?: boolean;
33
+ reason?: "not-order" | "no-asset" | "absent";
34
+ }
30
35
  /** The document's displayed grand total (data-quote-total) must equal the
31
36
  * engine total at penny precision — money is penny-precise, so a sub-penny
32
37
  * engine total (e.g. 3395.235) reconciles against the penny total the client
@@ -64,4 +69,14 @@ export declare function gateTermsWeight(html: string): TermsVerdict;
64
69
  * `1848/1` class, where the header says `1848` and the acceptance block says
65
70
  * `1848/1` — fails and reports the distinct values in first-seen order. */
66
71
  export declare function gateReferenceConsistency(html: string): RefVerdict;
72
+ /** An order-class document (marked `data-doc-order`) must embed the account's
73
+ * declared signature asset (`quoting/templates/signature.html`) verbatim — the
74
+ * operator's own signature block, its structure and embedded image data, not a
75
+ * rebuilt approximation. The order marker is the class signal, checked first: a
76
+ * document without it is not an order and is not checked (a plain quote carries
77
+ * no signature). An order with no declared asset skips (the same opt-in as the
78
+ * header template: no declared asset → no enforcement). An order with an asset
79
+ * declared must contain that asset verbatim (whitespace tolerant, the header
80
+ * mechanism); one that omits it fails closed — an unsigned order is not shipped. */
81
+ export declare function gateSignatureAsset(html: string, signatureTemplate: string | null): SignatureVerdict;
67
82
  //# sourceMappingURL=gates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../src/lib/gates.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AACnE,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,OAAO,CAAA;CAAE;AAC9C,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAAA;CAAE;AACzI,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,UAAU,CAAA;CAAE;AAC7G,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE;AAC5F,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AAExH;;;;;;;sEAOsE;AACtE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAMjF;AAED;8EAC8E;AAC9E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAExD;AAED;+EAC+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAS1D;AAUD;;;;;;;+DAO+D;AAC/D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAM1F;AA4BD;;;;iEAIiE;AACjE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAO1D;AAED;;;;;4EAK4E;AAC5E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAMjE"}
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../src/lib/gates.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,gBAAgB;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AACnE,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,OAAO,CAAA;CAAE;AAC9C,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAAA;CAAE;AACzI,MAAM,WAAW,aAAa;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,UAAU,CAAA;CAAE;AAC7G,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE;AAC5F,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AACxH,MAAM,WAAW,gBAAgB;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAA;CAAE;AAEpH;;;;;;;sEAOsE;AACtE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAMjF;AAED;8EAC8E;AAC9E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAExD;AAED;+EAC+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAS1D;AAUD;;;;;;;+DAO+D;AAC/D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAM1F;AA4BD;;;;iEAIiE;AACjE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAO1D;AAED;;;;;4EAK4E;AAC5E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAMjE;AAED;;;;;;;;qFAQqF;AACrF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAMnG"}
@@ -7,6 +7,7 @@
7
7
  // data-doc-header the header block (must be the declared canonical template verbatim)
8
8
  // data-doc-terms the standing-terms section (must carry no above-normal weight)
9
9
  // data-doc-ref every place the document reference appears (must all agree)
10
+ // data-doc-order the document is issued as an order (must embed the declared signature asset)
10
11
  /** The document's displayed grand total (data-quote-total) must equal the
11
12
  * engine total at penny precision — money is penny-precise, so a sub-penny
12
13
  * engine total (e.g. 3395.235) reconciles against the penny total the client
@@ -127,4 +128,22 @@ export function gateReferenceConsistency(html) {
127
128
  return { pass: true, ref: distinct[0] };
128
129
  return { pass: false, reason: "inconsistent", refs: distinct };
129
130
  }
131
+ /** An order-class document (marked `data-doc-order`) must embed the account's
132
+ * declared signature asset (`quoting/templates/signature.html`) verbatim — the
133
+ * operator's own signature block, its structure and embedded image data, not a
134
+ * rebuilt approximation. The order marker is the class signal, checked first: a
135
+ * document without it is not an order and is not checked (a plain quote carries
136
+ * no signature). An order with no declared asset skips (the same opt-in as the
137
+ * header template: no declared asset → no enforcement). An order with an asset
138
+ * declared must contain that asset verbatim (whitespace tolerant, the header
139
+ * mechanism); one that omits it fails closed — an unsigned order is not shipped. */
140
+ export function gateSignatureAsset(html, signatureTemplate) {
141
+ if (!/\bdata-doc-order\b/i.test(html))
142
+ return { pass: true, skipped: true, reason: "not-order" };
143
+ // A null or empty/whitespace-only template is "no signature asset declared":
144
+ // skip, rather than let `includes("")` report a pass that enforced nothing.
145
+ if (signatureTemplate === null || normaliseHtml(signatureTemplate) === "")
146
+ return { pass: true, skipped: true, reason: "no-asset" };
147
+ return normaliseHtml(html).includes(normaliseHtml(signatureTemplate)) ? { pass: true } : { pass: false, reason: "absent" };
148
+ }
130
149
  //# sourceMappingURL=gates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/lib/gates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/lib/gates.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type SignLinkVerdict } from "./gates.js";
2
- export type RenderFault = "render-absent" | "render-error" | "reconcile-fail" | "margin-leak" | "sign-link" | "header-mismatch" | "terms-weight" | "ref-inconsistent";
2
+ export type RenderFault = "render-absent" | "render-error" | "reconcile-fail" | "margin-leak" | "sign-link" | "header-mismatch" | "terms-weight" | "ref-inconsistent" | "signature-absent";
3
3
  export interface RunRenderArgs {
4
4
  accountDir: string;
5
5
  renderScriptPath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"render-run.d.ts","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"AAYA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,aAAa,GACb,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,kBAAkB,CAAC;AAEvB,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GACpB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,SAAS,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAGrE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAClC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAIvD,wBAAsB,SAAS,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAuIvE"}
1
+ {"version":3,"file":"render-run.d.ts","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"AAYA,OAAO,EAQL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,aAAa,GACb,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GACpB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,SAAS,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAGrE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAClC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAIvD,wBAAsB,SAAS,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAkJvE"}
@@ -9,7 +9,7 @@
9
9
  import { spawn } from "node:child_process";
10
10
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
11
11
  import { dirname, join } from "node:path";
12
- import { gateReconcile, gateMarginLeak, gateSignLink, gateHeaderConformance, gateTermsWeight, gateReferenceConsistency, } from "./gates.js";
12
+ import { gateReconcile, gateMarginLeak, gateSignLink, gateHeaderConformance, gateTermsWeight, gateReferenceConsistency, gateSignatureAsset, } from "./gates.js";
13
13
  import { writeRenderReceipt } from "./render-receipt.js";
14
14
  export async function runRender(a) {
15
15
  if (!existsSync(a.renderScriptPath)) {
@@ -95,9 +95,18 @@ export async function runRender(a) {
95
95
  const header = gateHeaderConformance(html.quote, headerTemplate);
96
96
  const terms = gateTermsWeight(html.quote);
97
97
  const ref = gateReferenceConsistency(html.quote);
98
+ // Order-class signature gate: when the render marks the client quote an order
99
+ // (data-doc-order), it must embed the account's declared signature asset
100
+ // (quoting/templates/signature.html, parallel to the header template). A
101
+ // non-order quote is not checked; an order with no declared asset skips. A
102
+ // marked order missing the declared asset fails closed, so an unsigned order
103
+ // writes no receipt and the browser-pdf-save gate then refuses the print.
104
+ const signatureAssetPath = join(a.accountDir, "quoting", "templates", "signature.html");
105
+ const signatureAsset = existsSync(signatureAssetPath) ? readFileSync(signatureAssetPath, "utf8") : null;
106
+ const signature = gateSignatureAsset(html.quote, signatureAsset);
98
107
  const internalOk = recInternal.pass;
99
108
  const breakdownOk = recBreakdown.pass && leakBreakdown.pass;
100
- const quoteOk = recQuote.pass && leakQuote.pass && signOk && header.pass && terms.pass && ref.pass;
109
+ const quoteOk = recQuote.pass && leakQuote.pass && signOk && header.pass && terms.pass && ref.pass && signature.pass;
101
110
  if (!internalOk || !breakdownOk || !quoteOk) {
102
111
  // Reason names the first failing gate, in document then gate order.
103
112
  let reason;
@@ -134,10 +143,14 @@ export async function runRender(a) {
134
143
  reason = "terms-weight";
135
144
  detail = "quote terms section carries above-normal font weight (bold/strong/font-weight >= 500)";
136
145
  }
137
- else {
146
+ else if (!ref.pass) {
138
147
  reason = "ref-inconsistent";
139
148
  detail = `quote document references disagree: ${(ref.refs ?? []).join(", ")}`;
140
149
  }
150
+ else {
151
+ reason = "signature-absent";
152
+ detail = "order-class quote (data-doc-order) does not embed the account's declared signature asset (quoting/templates/signature.html)";
153
+ }
141
154
  return { ok: false, reason, detail };
142
155
  }
143
156
  const internalPath = join(a.accountDir, "memory/admin/customers", phone, `quote-${a.jobId}-internal.html`);
@@ -1 +1 @@
1
- {"version":3,"file":"render-run.js","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render-run.js","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import {
6
6
  gateHeaderConformance,
7
7
  gateTermsWeight,
8
8
  gateReferenceConsistency,
9
+ gateSignatureAsset,
9
10
  } from "../gates.js";
10
11
 
11
12
  describe("gateReconcile — displayed total must equal the engine total", () => {
@@ -142,3 +143,27 @@ describe("gateReferenceConsistency — one document reference across every marke
142
143
  expect(gateReferenceConsistency(html)).toEqual({ pass: false, reason: "inconsistent", refs: ["1848", "1848/1"] });
143
144
  });
144
145
  });
146
+
147
+ describe("gateSignatureAsset — an order must embed the account's declared signature asset", () => {
148
+ const SIGNATURE = '<div data-doc-signature><img src="data:image/png;base64,AAAAsigBBBB"><span>A. Glazier, Director</span></div>';
149
+ it("skips a document that is not an order (no data-doc-order marker), even with an asset declared", () => {
150
+ expect(gateSignatureAsset("<body><h1>Quote</h1></body>", SIGNATURE)).toEqual({ pass: true, skipped: true, reason: "not-order" });
151
+ });
152
+ it("skips an order when the account declares no signature asset (template null)", () => {
153
+ expect(gateSignatureAsset('<body data-doc-order><h1>Order</h1></body>', null)).toEqual({ pass: true, skipped: true, reason: "no-asset" });
154
+ });
155
+ it("skips an order on an empty or whitespace-only declared asset rather than passing via includes(\"\")", () => {
156
+ expect(gateSignatureAsset('<body data-doc-order><h1>Order</h1></body>', " \n ")).toEqual({ pass: true, skipped: true, reason: "no-asset" });
157
+ });
158
+ it("passes when the order embeds the declared signature asset verbatim (whitespace-tolerant)", () => {
159
+ const rendered = `<body data-doc-order>\n <div data-doc-signature>\n <img src="data:image/png;base64,AAAAsigBBBB">\n <span>A. Glazier, Director</span>\n </div>\n</body>`;
160
+ expect(gateSignatureAsset(rendered, SIGNATURE)).toEqual({ pass: true });
161
+ });
162
+ it("fails an order that carries the order marker but omits the declared signature asset", () => {
163
+ expect(gateSignatureAsset('<body data-doc-order><h1>Order</h1><p>terms</p></body>', SIGNATURE)).toEqual({ pass: false, reason: "absent" });
164
+ });
165
+ it("fails an order whose signature block is a rebuilt approximation (different signer data)", () => {
166
+ const rebuilt = '<body data-doc-order><div data-doc-signature><img src="data:image/png;base64,AAAAsigBBBB"><span>Someone Else</span></div></body>';
167
+ expect(gateSignatureAsset(rebuilt, SIGNATURE)).toEqual({ pass: false, reason: "absent" });
168
+ });
169
+ });
@@ -268,6 +268,58 @@ process.stdin.on("end", () => {
268
268
  });
269
269
  });
270
270
 
271
+ describe("runRender — order-class signature-asset gate against a declared asset", () => {
272
+ let sdir: string;
273
+ const SIG_TPL = '<div data-doc-signature><img src="data:image/png;base64,AAAAsigBBBB"><span>A. Glazier, Director</span></div>';
274
+ // Emit a quote body that is either an order (data-doc-order) or a plain quote,
275
+ // optionally embedding a signature block. Brand/layout is the operator's; the
276
+ // tool only gates. No acceptance anchor (default, no-signer path).
277
+ const renderEmitting = (quoteBody: string) => `
278
+ let input = "";
279
+ process.stdin.on("data", (d) => (input += d));
280
+ process.stdin.on("end", () => {
281
+ const { figures } = JSON.parse(input);
282
+ const t = figures.total;
283
+ const quote = ${JSON.stringify(quoteBody)}.replace(/__T__/g, t);
284
+ process.stdout.write(JSON.stringify({
285
+ internal: '<html><body><td data-internal-only>c</td><p data-quote-total="' + t + '">Total ' + t + '</p></body></html>',
286
+ breakdown: '<html><body><p data-quote-total="' + t + '">Total ' + t + '</p></body></html>',
287
+ quote,
288
+ }));
289
+ });
290
+ `;
291
+ const ORDER_SIGNED = '<html><body data-doc-order><p data-quote-total="__T__">Total __T__</p>' + SIG_TPL + '</body></html>';
292
+ const ORDER_UNSIGNED = '<html><body data-doc-order><p data-quote-total="__T__">Total __T__</p></body></html>';
293
+ const PLAIN_QUOTE = '<html><body><p data-quote-total="__T__">Total __T__</p></body></html>';
294
+
295
+ beforeAll(() => {
296
+ sdir = mkdtempSync(join(tmpdir(), "sd-render-sig-"));
297
+ mkdirSync(join(sdir, "quoting", "templates"), { recursive: true });
298
+ writeFileSync(join(sdir, "quoting", "templates", "signature.html"), SIG_TPL);
299
+ writeFileSync(join(sdir, "quoting", "render-order-signed.mjs"), renderEmitting(ORDER_SIGNED));
300
+ writeFileSync(join(sdir, "quoting", "render-order-unsigned.mjs"), renderEmitting(ORDER_UNSIGNED));
301
+ writeFileSync(join(sdir, "quoting", "render-plain.mjs"), renderEmitting(PLAIN_QUOTE));
302
+ });
303
+ afterAll(() => rmSync(sdir, { recursive: true, force: true }));
304
+
305
+ it("passes when the order embeds the declared signature asset verbatim", async () => {
306
+ const r = await runRender({ accountDir: sdir, renderScriptPath: join(sdir, "quoting", "render-order-signed.mjs"), figures, jobId: "job-sig-ok" });
307
+ expect(r.ok).toBe(true);
308
+ expect(existsSync(receiptPath(sdir, "job-sig-ok"))).toBe(true);
309
+ });
310
+ it("signature-absent when the order omits the declared signature asset (fail-closed, nothing filed)", async () => {
311
+ const r = await runRender({ accountDir: sdir, renderScriptPath: join(sdir, "quoting", "render-order-unsigned.mjs"), figures, jobId: "job-sig-bad" });
312
+ expect(r).toMatchObject({ ok: false, reason: "signature-absent" });
313
+ expect(existsSync(join(sdir, "memory/users/44700900000/documents/quote-job-sig-bad.html"))).toBe(false);
314
+ expect(existsSync(receiptPath(sdir, "job-sig-bad"))).toBe(false);
315
+ });
316
+ it("files a plain quote (no order marker) even though a signature asset is declared — non-orders are not checked", async () => {
317
+ const r = await runRender({ accountDir: sdir, renderScriptPath: join(sdir, "quoting", "render-plain.mjs"), figures, jobId: "job-sig-plain" });
318
+ expect(r.ok).toBe(true);
319
+ expect(existsSync(receiptPath(sdir, "job-sig-plain"))).toBe(true);
320
+ });
321
+ });
322
+
271
323
  describe("runRender — script faults", () => {
272
324
  it("render-absent when the render script is missing", async () => {
273
325
  const r = await runRender({ accountDir: dir, renderScriptPath: rs("nope.mjs"), figures, signUrl, jobId });