From e24c3bf0e6480871a75e0cfc56ab644e2e2c0fc1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 13:06:47 +0000 Subject: [PATCH 1/2] fix(data): spell the head of legal and finance controller demo staff from keys.ts demoStaff spelled 'Head of Legal' and 'Finance Controller' as literals while src/data/keys.ts mirrored them as LEGAL_HEAD / FINANCE_CONTROLLER for reviewerOf(). clm_review.reviewer is required, so renaming one side dropped every review dealt to that account and the seed still reported success. Both entries now take their name from the same constant the fixture deals by, as the requesters and counsel already do. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn --- objectstack.config.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/objectstack.config.ts b/objectstack.config.ts index bf32d6d..51205df 100644 --- a/objectstack.config.ts +++ b/objectstack.config.ts @@ -7,7 +7,7 @@ import { allEmailTemplates } from './src/email-templates/index.js'; import * as profiles from './src/profiles/index.js'; import { CLM_POSITION, ClmPositions, ClmSharingRules } from './src/sharing/index.js'; import { clmSeeds, demoSeedRequested } from './src/data/index.js'; -import { CONTRACT_OWNERS, LEGAL_OWNERS } from './src/data/keys.js'; +import { CONTRACT_OWNERS, FINANCE_CONTROLLER, LEGAL_HEAD, LEGAL_OWNERS } from './src/data/keys.js'; import * as apps from './src/apps/index.js'; import * as datasets from './src/datasets/index.js'; import * as dashboards from './src/dashboards/index.js'; @@ -272,15 +272,19 @@ export default defineStack({ // password (`os dev --admin-password`, default `admin123`) — the platform // refuses a `password` key, so no credential is committed here. // - // - The business requesters and the two counsel are named by the SAME - // constants the fixture deals rows by (`src/data/keys.ts`), so a name here + // - Every account the fixture deals rows to BY NAME is named here by the + // SAME constant the fixture uses (`src/data/keys.ts`), so a name here // cannot drift from the `owner_id` / `legal_owner` / `owner` / - // `decided_by` values that resolve against it. A requester holds no - // position: `clm_requester` is every member's default set (`isDefault`). - // - The other six positions are staffed once each, so every rung of the + // `decided_by` / `reviewer` values that resolve against it: the business + // requesters, the two counsel, the head of legal and the finance + // controller. `reviewer` is `required`, so a drift there would not land + // NULL — the loader would drop every review dealt to the account and the + // seed would still report success. A requester holds no position: + // `clm_requester` is every member's default set (`isDefault`). + // - The other positions are staffed once each, so every rung of the // approval ladder and every audience group of §05 has someone to sign in - // as. The fixture names none of them; they are reached through the - // position, not by name. + // as. The fixture names none of the remaining four; they are reached + // through the position, not by name. // // ⚠️ A line manager cannot be declared: a `demoStaff` entry carries a // `position` and `permissionSets` and nothing else, and `sys_user.manager_id` @@ -290,8 +294,8 @@ export default defineStack({ ? [ ...CONTRACT_OWNERS.map((name, i) => ({ name, email: `requester${i + 1}@example.com` })), ...LEGAL_OWNERS.map((name, i) => ({ name, email: `counsel${i + 1}@example.com`, position: CLM_POSITION.legalCounsel })), - { name: 'Head of Legal', email: 'legal.head@example.com', position: CLM_POSITION.legalHead }, - { name: 'Finance Controller', email: 'finance@example.com', position: CLM_POSITION.financeController }, + { name: LEGAL_HEAD, email: 'legal.head@example.com', position: CLM_POSITION.legalHead }, + { name: FINANCE_CONTROLLER, email: 'finance@example.com', position: CLM_POSITION.financeController }, { name: 'Executive', email: 'executive@example.com', position: CLM_POSITION.executive }, { name: 'General Manager', email: 'gm@example.com', position: CLM_POSITION.generalManager }, { name: 'Records Manager', email: 'records@example.com', position: CLM_POSITION.recordsManager }, From b8b434205f76318afe04c1b3a32dfccdd940d5c3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 13:23:11 +0000 Subject: [PATCH 2/2] keys.ts: the staff-name comment says config spells them from here (#191) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn --- src/data/keys.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/keys.ts b/src/data/keys.ts index 2cedac9..187c5b1 100644 --- a/src/data/keys.ts +++ b/src/data/keys.ts @@ -315,11 +315,11 @@ export const deviationDeciderOf = (deviation: DeviationPlan): string | null => * The head of legal and the finance controller, as the ACCOUNT NAMES the * loader resolves `clm_review.reviewer` against. * - * ⚠️ These two MIRROR the `name` of their `demoStaff` entries in - * `objectstack.config.ts`, which spells them as literals rather than from - * here. `reviewer` is `required: true`, so a drift between the two is not a - * NULL but a lost row: the loader refuses every review that names an account - * nobody carries, and the seed reports success for the rest. + * These two are the `name` of their `demoStaff` entries in + * `objectstack.config.ts`, which spells them from here, so a rename moves + * both (issue #191). `reviewer` is `required: true`, which is why they must + * never drift: the loader refuses every review that names an account nobody + * carries, and the seed reports success for the rest. */ export const LEGAL_HEAD = 'Head of Legal'; export const FINANCE_CONTROLLER = 'Finance Controller';