fraim-hub 2.0.288 → 2.0.289

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.
@@ -6332,14 +6332,10 @@ class AiHubServer {
6332
6332
  messages: persistedConversation ? persistedMessagesForRun(persistedConversation) : [],
6333
6333
  events: resumeEvents,
6334
6334
  eventLogRefs: persistedConversation?.eventLogRefs || [],
6335
- // Issue #1373: a conversation is permanently scoped to one job for its
6336
- // lifetime, including after that job's conversation is marked
6337
- // 'completed' a coaching turn sent to a Done job resumes the SAME
6338
- // job's phase history, it does not start unrelated new work. Always
6339
- // carry the persisted run projection forward regardless of the
6340
- // conversation's prior status. If the resumed session genuinely has
6341
- // nothing left to do, it simply reaches the same completed state
6342
- // again on its own the next time seekMentoring reports its phase.
6335
+ // A manager can issue new instructions after a job was marked done.
6336
+ // That correction stays in the same conversation/job identity and keeps
6337
+ // its phase history so the tracker can show the job moving back to an
6338
+ // earlier phase instead of pretending this is unrelated fresh work.
6343
6339
  currentPhase: persistedRun?.currentPhase || null,
6344
6340
  phaseHistory: persistedRun?.phaseHistory || [],
6345
6341
  phaseVisits: persistedRun?.phaseVisits || [],
@@ -64,13 +64,17 @@ function buildSearchQuery(roleKey) {
64
64
  const profile = getHumanManagerProfile(roleKey);
65
65
  return `${profile.keywords.join(' OR ')} AND ${AI_MANAGER_QUERY_TERMS}`;
66
66
  }
67
+ function indefiniteArticle(phrase) {
68
+ return /^[aeiou]/i.test(phrase.trim()) ? 'an' : 'a';
69
+ }
67
70
  function buildJobDescription(roleKey) {
68
71
  const profile = getHumanManagerProfile(roleKey);
69
72
  const role = persona_hiring_1.PERSONA_HIRE_CATALOG[roleKey]?.role ?? 'AI Employee';
73
+ const article = indefiniteArticle(role);
70
74
  return [
71
- `${profile.humanTitle} — manager for an ${role}`,
75
+ `${profile.humanTitle} — manager for ${article} ${role}`,
72
76
  '',
73
- `You will manage an ${role} (an autonomous AI agent) and the humans around it, owning the outcomes it ships.`,
77
+ `You will manage ${article} ${role} (an autonomous AI agent) and the humans around it, owning the outcomes it ships.`,
74
78
  '',
75
79
  "What you'll do:",
76
80
  `- Write crisp specifications and acceptance criteria the ${role} can execute against.`,
@@ -278,7 +278,7 @@ exports.PERSONA_CAPABILITY_BUNDLES = {
278
278
  ],
279
279
  protectedAliases: ['ai-engineering', 'agent-engineering', 'ai-agents'],
280
280
  defaultHireMode: 'job',
281
- lockCopy: 'Hire AIda to unlock AI agent design, MCP enablement, eval authoring, and agent evaluation work for this request.'
281
+ lockCopy: 'Hire AIDa to unlock AI agent design, MCP enablement, eval authoring, and agent evaluation work for this request.'
282
282
  }
283
283
  };
284
284
  const PROTECTED_JOB_TO_PERSONA = new Map();
@@ -20,8 +20,8 @@ exports.getPersonaHireAmountCents = getPersonaHireAmountCents;
20
20
  */
21
21
  exports.PERSONA_HIRE_CATALOG = {
22
22
  aida: {
23
- displayName: 'AIda',
24
- role: 'AI Engineer',
23
+ displayName: 'AIDa',
24
+ role: 'AI Developer',
25
25
  emoji: '\u{1F9E0}',
26
26
  gradient: 'linear-gradient(135deg, #4f46e5 0%, #06b6d4 50%, #10b981 100%)',
27
27
  blurb: 'Designs production AI agents, connects them to tools and data, and proves their behavior with evals before deployment.',
@@ -30,7 +30,7 @@ exports.PERSONA_HIRE_CATALOG = {
30
30
  },
31
31
  swen: {
32
32
  displayName: 'SWEn',
33
- role: 'AI Software Engineer',
33
+ role: 'Software Engineer',
34
34
  emoji: '💻',
35
35
  gradient: 'linear-gradient(135deg, #2563eb 0%, #06b6d4 100%)',
36
36
  blurb: 'Implements features, refactors code, and drives PR iteration to merge, reviewing design and code as a senior would.',
@@ -39,7 +39,7 @@ exports.PERSONA_HIRE_CATALOG = {
39
39
  },
40
40
  qasm: {
41
41
  displayName: 'QAsm',
42
- role: 'AI QA Engineer',
42
+ role: 'QA Engineer',
43
43
  emoji: '🛡️',
44
44
  gradient: 'linear-gradient(135deg, #10b981 0%, #14b8a6 100%)',
45
45
  blurb: 'Runs tests, assesses code and test quality, polishes UI, and drives bug bashes with evidence.',
@@ -48,7 +48,7 @@ exports.PERSONA_HIRE_CATALOG = {
48
48
  },
49
49
  sekhar: {
50
50
  displayName: 'SEChar',
51
- role: 'AI Security Engineer',
51
+ role: 'Security Engineer',
52
52
  emoji: '🔒',
53
53
  gradient: 'linear-gradient(135deg, #ef4444 0%, #f43f5e 100%)',
54
54
  blurb: 'Sets up AI-native security baselines, runs the findings command center, reviews changes for risk, and drives remediation to closure.',
@@ -57,7 +57,7 @@ exports.PERSONA_HIRE_CATALOG = {
57
57
  },
58
58
  sreya: {
59
59
  displayName: 'SREya',
60
- role: 'AI Site Reliability Engineer',
60
+ role: 'Site Reliability Engineer',
61
61
  emoji: '☁️',
62
62
  gradient: 'linear-gradient(135deg, #2563eb 0%, #10b981 100%)',
63
63
  blurb: 'Manages deployments, monitors uptime, optimizes cloud cost, and keeps infrastructure resilient and observable.',
@@ -66,7 +66,7 @@ exports.PERSONA_HIRE_CATALOG = {
66
66
  },
67
67
  sade: {
68
68
  displayName: 'SADE',
69
- role: 'AI Salesforce Developer',
69
+ role: 'Salesforce Developer',
70
70
  emoji: '☁️',
71
71
  gradient: 'linear-gradient(135deg, #0284c7 0%, #0369a1 100%)',
72
72
  blurb: 'Deploys Salesforce configuration from ServiceNow tickets, builds reports and dashboards, creates Flows from business requirements, audits org health, and manages users and data at scale.',
@@ -75,7 +75,7 @@ exports.PERSONA_HIRE_CATALOG = {
75
75
  },
76
76
  pam: {
77
77
  displayName: 'PaM',
78
- role: 'AI Product Manager',
78
+ role: 'Product Manager',
79
79
  emoji: '📋',
80
80
  gradient: 'linear-gradient(135deg, #8b5cf6 0%, #d946ef 100%)',
81
81
  blurb: 'Owns specs, PRDs, technical design, issue prep, and the path from idea to shippable artifact.',
@@ -84,7 +84,7 @@ exports.PERSONA_HIRE_CATALOG = {
84
84
  },
85
85
  huxley: {
86
86
  displayName: 'hUXley',
87
- role: 'AI UX / Brand Designer',
87
+ role: 'UX / Brand Designer',
88
88
  emoji: '🎨',
89
89
  gradient: 'linear-gradient(135deg, #ec4899 0%, #f472b6 100%)',
90
90
  blurb: 'Builds design systems, prototypes polished user-facing surfaces, and carries brand decisions into shipped product experiences.',
@@ -93,7 +93,7 @@ exports.PERSONA_HIRE_CATALOG = {
93
93
  },
94
94
  gautam: {
95
95
  displayName: 'GauTaM',
96
- role: 'AI GTM & Marketing Manager',
96
+ role: 'GTM & Marketing Manager',
97
97
  emoji: '📣',
98
98
  gradient: 'linear-gradient(135deg, #f97316 0%, #f59e0b 100%)',
99
99
  blurb: 'Defines marketing strategy, ships content, runs launches, and owns the brand voice in market.',
@@ -102,7 +102,7 @@ exports.PERSONA_HIRE_CATALOG = {
102
102
  },
103
103
  sam: {
104
104
  displayName: 'SAM',
105
- role: 'AI Sales Account Manager',
105
+ role: 'Sales Account Manager',
106
106
  emoji: '📈',
107
107
  gradient: 'linear-gradient(135deg, #059669 0%, #0d9488 100%)',
108
108
  blurb: 'Surfaces stalled deals, computes pipeline health, and drafts account-specific re-engagement proposals for your top at-risk opportunities.',
@@ -111,7 +111,7 @@ exports.PERSONA_HIRE_CATALOG = {
111
111
  },
112
112
  casey: {
113
113
  displayName: 'CaSey',
114
- role: 'AI Customer Success + Support',
114
+ role: 'Customer Success + Support',
115
115
  emoji: '💬',
116
116
  gradient: 'linear-gradient(135deg, #db2777 0%, #9333ea 100%)',
117
117
  blurb: 'Scores account churn risk and expansion potential, generates prioritized action plans for CSMs, triages support cases, and routes L1 cases through automated resolution.',
@@ -120,7 +120,7 @@ exports.PERSONA_HIRE_CATALOG = {
120
120
  },
121
121
  mona: {
122
122
  displayName: 'MONa',
123
- role: 'AI Finance Manager',
123
+ role: 'Finance Manager',
124
124
  emoji: '💰',
125
125
  gradient: 'linear-gradient(135deg, #10b981 0%, #f59e0b 100%)',
126
126
  blurb: 'Models revenue, tracks unit economics, builds financial forecasts, and owns the metrics that drive growth decisions.',
@@ -129,7 +129,7 @@ exports.PERSONA_HIRE_CATALOG = {
129
129
  },
130
130
  hari: {
131
131
  displayName: 'HaRi',
132
- role: 'AI HR Manager',
132
+ role: 'HR Manager',
133
133
  emoji: '👥',
134
134
  gradient: 'linear-gradient(135deg, #0d9488 0%, #059669 100%)',
135
135
  blurb: 'Manages onboarding, performance reviews, benefits analysis, payroll coordination, and HR business-partner advisory.',
@@ -138,7 +138,7 @@ exports.PERSONA_HIRE_CATALOG = {
138
138
  },
139
139
  ricardo: {
140
140
  displayName: 'RECardo',
141
- role: 'AI Recruiter',
141
+ role: 'Recruiter',
142
142
  emoji: '🤝',
143
143
  gradient: 'linear-gradient(135deg, #6366f1 0%, #ec4899 100%)',
144
144
  blurb: 'Sources candidates, writes job descriptions, screens pipelines, and manages the hiring loop end-to-end.',
@@ -147,7 +147,7 @@ exports.PERSONA_HIRE_CATALOG = {
147
147
  },
148
148
  cela: {
149
149
  displayName: 'CELiA',
150
- role: 'AI Legal Counsel',
150
+ role: 'Legal Counsel',
151
151
  emoji: '⚖️',
152
152
  gradient: 'linear-gradient(135deg, #475569 0%, #6366f1 100%)',
153
153
  blurb: 'Drafts and reviews contracts, NDAs, patents, trademarks, and the SaaS legal stack.',
@@ -156,7 +156,7 @@ exports.PERSONA_HIRE_CATALOG = {
156
156
  },
157
157
  procella: {
158
158
  displayName: 'PROCella',
159
- role: 'AI Procurement Manager',
159
+ role: 'Procurement Manager',
160
160
  emoji: '📦',
161
161
  gradient: 'linear-gradient(135deg, #0f766e 0%, #7c3aed 100%)',
162
162
  blurb: 'Frames procurement strategy, sources suppliers, runs RFx packages, evaluates responses, and keeps purchases acceptance-gated.',
@@ -165,7 +165,7 @@ exports.PERSONA_HIRE_CATALOG = {
165
165
  },
166
166
  banke: {
167
167
  displayName: 'BANKe',
168
- role: 'AI Banking KYC Employee',
168
+ role: 'Banking KYC Employee',
169
169
  emoji: '\u{1F3E6}',
170
170
  gradient: 'linear-gradient(135deg, #0f766e 0%, #2563eb 100%)',
171
171
  blurb: 'Runs banking KYC cases with consent-aware evidence capture, decision receipts, and stable audit handoff artifacts.',
@@ -174,7 +174,7 @@ exports.PERSONA_HIRE_CATALOG = {
174
174
  },
175
175
  auditya: {
176
176
  displayName: 'AUDITya',
177
- role: 'AI Banking Auditor',
177
+ role: 'Banking Auditor',
178
178
  emoji: '\u{1F50E}',
179
179
  gradient: 'linear-gradient(135deg, #7c3aed 0%, #0f172a 100%)',
180
180
  blurb: 'Audits AI banking work by tracing decisions back to evidence, receipts, exceptions, and reusable audit reports.',
@@ -183,7 +183,7 @@ exports.PERSONA_HIRE_CATALOG = {
183
183
  },
184
184
  deidre: {
185
185
  displayName: 'DEIdre',
186
- role: 'AI Inclusion Leader',
186
+ role: 'Inclusion Leader',
187
187
  emoji: '🌍',
188
188
  gradient: 'linear-gradient(135deg, #9333ea 0%, #d946ef 100%)',
189
189
  blurb: 'Audits equity gaps, designs bias-aware AI governance, builds ERG toolkits, and creates inclusion-fluency programs.',
@@ -192,7 +192,7 @@ exports.PERSONA_HIRE_CATALOG = {
192
192
  },
193
193
  careena: {
194
194
  displayName: 'CAREEna',
195
- role: 'AI Career Coach',
195
+ role: 'Career Coach',
196
196
  emoji: '🎓',
197
197
  gradient: 'linear-gradient(135deg, #0ea5e9 0%, #6366f1 100%)',
198
198
  blurb: 'Runs the candidate-side search loop: role sourcing, application execution, networking, interview prep, and close-stage offer strategy.',
@@ -201,7 +201,7 @@ exports.PERSONA_HIRE_CATALOG = {
201
201
  },
202
202
  ashley: {
203
203
  displayName: 'AshLey',
204
- role: 'AI Executive Assistant',
204
+ role: 'Executive Assistant',
205
205
  emoji: '📅',
206
206
  gradient: 'linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%)',
207
207
  blurb: 'Owns executive coordination, weekly operating reviews, and portfolio reporting across the workforce.',
@@ -210,7 +210,7 @@ exports.PERSONA_HIRE_CATALOG = {
210
210
  },
211
211
  mandy: {
212
212
  displayName: 'MANdy',
213
- role: 'AI Manager',
213
+ role: 'Manager',
214
214
  emoji: '🎯',
215
215
  gradient: 'linear-gradient(135deg, #7c3aed 0%, #4338ca 100%)',
216
216
  blurb: 'Plans the job sequence, runs sub-agents in parallel, coaches them through verification loops, and hands back a synthesized DRAFT for your approval.',
@@ -219,7 +219,7 @@ exports.PERSONA_HIRE_CATALOG = {
219
219
  },
220
220
  beza: {
221
221
  displayName: 'BeZa',
222
- role: 'AI Business Strategist',
222
+ role: 'Business Strategist',
223
223
  emoji: '🧭',
224
224
  gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
225
225
  blurb: 'Turns ideas into structured business plans, validates founder-market fit, and pressure-tests strategy.',
@@ -228,7 +228,7 @@ exports.PERSONA_HIRE_CATALOG = {
228
228
  },
229
229
  maestro: {
230
230
  displayName: 'MAESTRO',
231
- role: 'Full-Brained AI Employee',
231
+ role: 'Full-Brained Employee',
232
232
  emoji: '★',
233
233
  gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%)',
234
234
  blurb: 'One AI employee who can take a job from any function and ship it back with evidence. You set the direction. You sign off on what ships. Maestro does the work.',
@@ -260,7 +260,7 @@ exports.PERSONA_AVATAR_CATALOG = {
260
260
  procella: { seed: 'PROCELLA-procurement', bg: 'ccfbf1', style: 'notionists' },
261
261
  banke: { seed: 'BANKe-banking-kyc', bg: 'ccfbf1', style: 'notionists' },
262
262
  auditya: { seed: 'AUDITya-banking-audit', bg: 'e9d5ff', style: 'notionists' },
263
- aida: { seed: 'AIda-ai-engineer', bg: 'c7d2fe', style: 'notionists' },
263
+ aida: { seed: 'AIDa-ai-developer', bg: 'c7d2fe', style: 'notionists' },
264
264
  };
265
265
  function buildPersonaAvatarUrl(personaKey) {
266
266
  const avatar = exports.PERSONA_AVATAR_CATALOG[personaKey];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-hub",
3
- "version": "2.0.288",
3
+ "version": "2.0.289",
4
4
  "description": "FRAIM Hub local companion package.",
5
5
  "author": "Sid Mathur <sid.mathur@gmail.com>",
6
6
  "homepage": "https://github.com/mathursrus/FRAIM#readme",
@@ -210,7 +210,7 @@
210
210
  "electron-updater": "^6.8.9",
211
211
  "express": "^5.2.1",
212
212
  "extract-zip": "^2.0.1",
213
- "fraim": "2.0.288",
213
+ "fraim": "2.0.289",
214
214
  "mongodb": "^7.0.0",
215
215
  "node-cron": "4.2.1",
216
216
  "node-edge-tts": "^1.2.10",
@@ -23,7 +23,7 @@ const PAGE_SCOPED_JOBS = new Set(['organization-onboarding', 'manager-agreements
23
23
  // invokedArea left runs started from the "wrong" tab unreachable from either rail.
24
24
  // Issue #702: personas whose home is the MANAGER tab because their work is inherently
25
25
  // cross-project and manager-facing (not project work). Per the spec (R1b), Ashley — the
26
- // AI Executive Assistant is Manager-scoped. Every other hired persona works inside
26
+ // Executive Assistant is Manager-scoped. Every other hired persona works inside
27
27
  // projects and belongs on the Projects tab only, NOT the Manager rail. Add a key here
28
28
  // to surface a new manager-scoped persona.
29
29
  const MANAGER_PERSONA_KEYS = new Set(['ashley']);
@@ -1156,7 +1156,6 @@ const SERVER_OWNED_CONV_FIELDS = ['messages', 'events', 'artifacts', 'run', 'del
1156
1156
  // any inbound value. That is what preserves issue #913: a marker arriving over
1157
1157
  // the wire is never trusted, only one this client set after a real fetch.
1158
1158
  const CLIENT_ONLY_CONV_FIELDS = ['_bodyLoaded', '_bodyFetched', '_stopping'];
1159
- const FULL_BODY_CONV_FIELDS = ['messages', 'events', 'artifacts', 'run', 'handoffSummary'];
1160
1159
  function slimConversationForPersist(conv) {
1161
1160
  if (!conv || typeof conv !== 'object') return conv;
1162
1161
  const slim = { ...conv };
@@ -1175,7 +1174,13 @@ function conversationHasBody(conv) {
1175
1174
  // instead of looping. Issue #913 stays satisfied because `_bodyFetched` is
1176
1175
  // client-only and stripped from every inbound header.
1177
1176
  if (conv._bodyFetched === true) return true;
1178
- return FULL_BODY_CONV_FIELDS.some((field) => Object.prototype.hasOwnProperty.call(conv, field));
1177
+ // Issue #1416: `messages` is the only field that proves the transcript was actually
1178
+ // fetched. `events`/`artifacts`/`run`/`handoffSummary` can each arrive independently
1179
+ // via a lightweight status update (e.g. conversationDispatchAgentId()'s restart-recovery
1180
+ // notice sets `events` alone) without the message transcript ever having been fetched.
1181
+ // Treating any one of them as sufficient permanently short-circuited hydration for
1182
+ // Manager/Company conversations that picked up one of those fields first.
1183
+ return Object.prototype.hasOwnProperty.call(conv, 'messages');
1179
1184
  }
1180
1185
 
1181
1186
  function cleanConversationHeader(header) {
@@ -1821,7 +1826,7 @@ function coachEmployeeLabel(conv) {
1821
1826
  const emp = getEmployeeStatus(agentName);
1822
1827
  if (emp) return emp.label;
1823
1828
  }
1824
- return 'Maestro';
1829
+ return NO_FRAIM_EMPLOYEE_LABEL;
1825
1830
  }
1826
1831
 
1827
1832
  // R3: resolve the logged-in manager's first name for dynamic panel kickers.
@@ -2936,6 +2941,7 @@ function conversationHasFraimEmployee(conv) {
2936
2941
  }
2937
2942
 
2938
2943
  function getEmployeeStatus(employeeId) {
2944
+ if (!employeeId) return null;
2939
2945
  const baseId = baseHostIdForAgent(employeeId);
2940
2946
  return (state.bootstrap?.employees || []).find((employee) => employee.id === baseId) || null;
2941
2947
  }
@@ -13135,16 +13141,40 @@ function tfBuildManagerRunItem(conv) {
13135
13141
  return btn;
13136
13142
  }
13137
13143
 
13144
+ // #1416: capture each employee group's open/closed state from the area rail (Manager or
13145
+ // Company) before it is rebuilt, mirroring renderRail()'s preservedEmployeeGroupOpen() for
13146
+ // the Projects rail. Without this, tfRenderManager()/tfRenderCompany()'s ~1-1.5s poll-driven
13147
+ // rebuild wiped the DOM and re-created every group, so a manually collapsed group snapped
13148
+ // back open on the next tick and there was no way to tell a no-run group from one the user
13149
+ // deliberately expanded.
13150
+ function captureAreaEmployeeGroupOpenState(rail) {
13151
+ const openState = new Map();
13152
+ if (!rail) return openState;
13153
+ rail.querySelectorAll('details.conv-employee-group[data-employee-key]').forEach((details) => {
13154
+ const key = details.dataset ? details.dataset.employeeKey : '';
13155
+ if (key) openState.set(key, details.open);
13156
+ });
13157
+ return openState;
13158
+ }
13159
+
13138
13160
  // #702: render a hired persona as an employee group on the Manager rail — the SAME
13139
13161
  // visual as the Projects rail employee groups (avatar + name + role + count + "+" that
13140
13162
  // opens the job palette), with the persona's MANAGER-invoked runs listed under it.
13141
13163
  // Keeps a persona looking like an employee, consistent across tabs.
13142
- function tfRenderAreaPersonaGroup(rail, persona, area) {
13164
+ function tfRenderAreaPersonaGroup(rail, persona, area, employeeGroupOpenState) {
13143
13165
  const sample = { personaKey: persona.key };
13144
13166
  const runs = tfAreaScopedConversations(area).filter((c) => c.personaKey === persona.key);
13145
13167
  const details = document.createElement('details');
13146
13168
  details.className = 'conv-employee-group';
13147
- details.open = true;
13169
+ details.dataset.employeeKey = persona.key;
13170
+ // #1416: preserve the user's toggle across the poll-driven rebuild. A group with no
13171
+ // prior state (first render) defaults open only if it has an active run — e.g. the
13172
+ // owning employee's currently-running job — same "has an active run, or you manually
13173
+ // expanded it" contract the issue calls out for the Projects rail; otherwise collapsed.
13174
+ const defaultOpen = runs.some((c) => conversationUiState(c) !== 'complete');
13175
+ details.open = employeeGroupOpenState && employeeGroupOpenState.has(persona.key)
13176
+ ? employeeGroupOpenState.get(persona.key)
13177
+ : defaultOpen;
13148
13178
  const summary = document.createElement('summary');
13149
13179
  summary.className = 'conv-employee-tab';
13150
13180
  const avatar = buildConversationEmployeeAvatar(sample, 'conv-employee-avatar');
@@ -13187,7 +13217,7 @@ function tfRenderAreaPersonaGroup(rail, persona, area) {
13187
13217
  // is the area's own top-level job run (manager-agreements / org onboarding) or any other
13188
13218
  // run with no persona group to live under; it gets its own rail entry unless a group
13189
13219
  // below will already list it.
13190
- function tfRenderAreaEmployeeRail(rail, area, ownerlessConv) {
13220
+ function tfRenderAreaEmployeeRail(rail, area, ownerlessConv, employeeGroupOpenState) {
13191
13221
  const areaPersonas = tfAreaRailPersonas(area);
13192
13222
  // A group only actually lists conversations tfAreaScopedConversations(area) returns
13193
13223
  // (i.e. correctly scope/invokedArea-tagged). A legacy conv that predates that tagging
@@ -13204,7 +13234,7 @@ function tfRenderAreaEmployeeRail(rail, area, ownerlessConv) {
13204
13234
  rail.appendChild(head);
13205
13235
  any = true;
13206
13236
  }
13207
- tfRenderAreaPersonaGroup(rail, persona, area);
13237
+ tfRenderAreaPersonaGroup(rail, persona, area, employeeGroupOpenState);
13208
13238
  }
13209
13239
  if (any) {
13210
13240
  const pNote = document.createElement('div'); pNote.className = 'area-rail-note';
@@ -13259,6 +13289,9 @@ function tfRenderCompany() {
13259
13289
  if (!state.brandEditorDraftActive && typeof tfRenderBrandEditor === 'function') tfRenderBrandEditor();
13260
13290
  const rail = document.getElementById('company-rail');
13261
13291
  if (rail) {
13292
+ // #1416: capture the current open/closed state before wiping the rail so the
13293
+ // ~1.5s poll-driven rebuild below doesn't snap a manually collapsed group back open.
13294
+ const employeeGroupOpenState = captureAreaEmployeeGroupOpenState(rail);
13262
13295
  rail.innerHTML = '';
13263
13296
  const orgConv = tfActiveOrgConv();
13264
13297
  const orgConvActive = !!orgConv;
@@ -13277,7 +13310,7 @@ function tfRenderCompany() {
13277
13310
  // #1398: FRAIMworker (and any hired employee with a company-scoped run, e.g. Aida)
13278
13311
  // get the same employee-group presentation as the Manager rail — not just an orphan
13279
13312
  // entry for the single "most active" org conv.
13280
- tfRenderAreaEmployeeRail(rail, 'company', orgConv);
13313
+ tfRenderAreaEmployeeRail(rail, 'company', orgConv, employeeGroupOpenState);
13281
13314
  tfReopenPendingRunDelete(rail);
13282
13315
  }
13283
13316
  const profile = document.getElementById('company-profile');
@@ -13424,6 +13457,9 @@ function tfRenderManager() {
13424
13457
  // #521 R6: manager-level job (manager-agreements) lives ONLY in this left rail.
13425
13458
  const rail = document.getElementById('manager-rail');
13426
13459
  if (rail) {
13460
+ // #1416: capture the current open/closed state before wiping the rail so the
13461
+ // ~1s poll-driven rebuild below doesn't snap a manually collapsed group back open.
13462
+ const employeeGroupOpenState = captureAreaEmployeeGroupOpenState(rail);
13427
13463
  rail.innerHTML = '';
13428
13464
  const mgrConv = tfActiveMgrConv();
13429
13465
  const mgrConvActive = !!mgrConv;
@@ -13440,7 +13476,7 @@ function tfRenderManager() {
13440
13476
  // Aida's manager-scoped runs) — the same avatar + name + runs + "+" presentation as the
13441
13477
  // Projects rail. `mgrConv` (the area's own top-level run, e.g. manager-agreements) gets
13442
13478
  // its own rail entry unless a group above already lists it.
13443
- tfRenderAreaEmployeeRail(rail, 'manager', mgrConv);
13479
+ tfRenderAreaEmployeeRail(rail, 'manager', mgrConv, employeeGroupOpenState);
13444
13480
  // #824: the manager rail also attaches run-delete controls; re-attach an open
13445
13481
  // confirm this innerHTML='' rebuild would otherwise drop.
13446
13482
  tfReopenPendingRunDelete(rail);
@@ -717,7 +717,16 @@
717
717
  }
718
718
  };
719
719
  submit.addEventListener('click', onSubmit);
720
- input.addEventListener('keydown', (e) => { if (e.key === 'Enter') onSubmit(); });
720
+ input.addEventListener('keydown', (e) => {
721
+ if (e.key === 'Enter') {
722
+ onSubmit();
723
+ return;
724
+ }
725
+ if (e.key === 'Tab' && !e.shiftKey) {
726
+ e.preventDefault();
727
+ submit.focus();
728
+ }
729
+ });
721
730
  card.appendChild(submit);
722
731
 
723
732
  CHECKLIST_EL.appendChild(card);
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AIda · AI Engineer · FRAIM Portfolio</title>
6
+ <title>AIDa · AI Developer · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -99,15 +99,15 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
99
99
 
100
100
  <section class="hero">
101
101
  <div class="avatar-ring">
102
- <img src="https://api.dicebear.com/9.x/notionists/svg?seed=AIda-ai-engineer&backgroundColor=c7d2fe&radius=50" width="96" height="96" alt="AIda avatar" style="border-radius:50%;">
102
+ <img src="https://api.dicebear.com/9.x/notionists/svg?seed=AIDa-ai-developer&backgroundColor=c7d2fe&radius=50" width="96" height="96" alt="AIDa avatar" style="border-radius:50%;">
103
103
  </div>
104
104
  <div class="role-chip">AI ENGINEERING</div>
105
- <h1>Meet <span>AIda</span></h1>
106
- <p>Agents that work. Evals that prove it. AIda can design production AI agents, connect them to tools and data, and validate their behavior end to end.</p>
105
+ <h1>Meet <span>AIDa</span></h1>
106
+ <p>Agents that work. Evals that prove it. AIDa can design production AI agents, connect them to tools and data, and validate their behavior end to end.</p>
107
107
  </section>
108
108
 
109
109
  <div class="section-label">
110
- <h2>What AIda Can Build</h2>
110
+ <h2>What AIDa Can Build</h2>
111
111
  <div class="section-divider"></div>
112
112
  </div>
113
113
 
@@ -128,10 +128,10 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
128
128
  <div class="narrative">
129
129
  <div class="narrative-step">
130
130
  <div class="step-label">The Ask</div>
131
- <div class="step-text">A team can describe a use case and a target platform. AIda can scope the agent design, instructions, tool/knowledge configuration, and deployment package.</div>
131
+ <div class="step-text">A team can describe a use case and a target platform. AIDa can scope the agent design, instructions, tool/knowledge configuration, and deployment package.</div>
132
132
  </div>
133
133
  <div class="narrative-step">
134
- <div class="step-label">What AIda Can Build</div>
134
+ <div class="step-label">What AIDa Can Build</div>
135
135
  <div class="step-text">An agent definition, platform-specific deployment package, tool permissions evidence, and a validation walkthrough against the intended use case.</div>
136
136
  </div>
137
137
  <div class="narrative-step">
@@ -165,10 +165,10 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
165
165
  <div class="narrative">
166
166
  <div class="narrative-step">
167
167
  <div class="step-label">The Ask</div>
168
- <div class="step-text">A team can supply a dataset, success criteria, and the agent or model under test. AIda can structure evaluation cases covering task completion, tool use, hallucination, and safety.</div>
168
+ <div class="step-text">A team can supply a dataset, success criteria, and the agent or model under test. AIDa can structure evaluation cases covering task completion, tool use, hallucination, and safety.</div>
169
169
  </div>
170
170
  <div class="narrative-step">
171
- <div class="step-label">What AIda Can Build</div>
171
+ <div class="step-label">What AIDa Can Build</div>
172
172
  <div class="step-text">A runner-compatible eval suite with dataset provenance, metric definitions, approval-evidenced thresholds, and an executed baseline result.</div>
173
173
  </div>
174
174
  <div class="narrative-step">
@@ -194,10 +194,10 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
194
194
  <div class="narrative">
195
195
  <div class="narrative-step">
196
196
  <div class="step-label">The Ask</div>
197
- <div class="step-text">A team can name the target web product and the capabilities to expose. AIda can handle transport, authentication, least-privilege tool selection, and client connection instructions.</div>
197
+ <div class="step-text">A team can name the target web product and the capabilities to expose. AIDa can handle transport, authentication, least-privilege tool selection, and client connection instructions.</div>
198
198
  </div>
199
199
  <div class="narrative-step">
200
- <div class="step-label">What AIda Can Build</div>
200
+ <div class="step-label">What AIDa Can Build</div>
201
201
  <div class="step-text">A functioning MCP server for the target product, with authentication wired, a tool manifest, and verified connection instructions for AI clients including Claude, Cursor, and GitHub Copilot.</div>
202
202
  </div>
203
203
  <div class="narrative-step">
@@ -223,10 +223,10 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
223
223
  <div class="narrative">
224
224
  <div class="narrative-step">
225
225
  <div class="step-label">The Ask</div>
226
- <div class="step-text">A team can supply a baseline agent and evaluation dataset. AIda can run the evaluation using the platform's supported interface or the repository's existing eval harness.</div>
226
+ <div class="step-text">A team can supply a baseline agent and evaluation dataset. AIDa can run the evaluation using the platform's supported interface or the repository's existing eval harness.</div>
227
227
  </div>
228
228
  <div class="narrative-step">
229
- <div class="step-label">What AIda Can Build</div>
229
+ <div class="step-label">What AIDa Can Build</div>
230
230
  <div class="step-text">A scored evaluation artifact linking each result to its evaluator, dataset version, run timestamp, and trace evidence location.</div>
231
231
  </div>
232
232
  <div class="narrative-step">
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AshLey · AI Executive Assistant · FRAIM Portfolio</title>
6
+ <title>AshLey · Executive Assistant · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -233,7 +233,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
233
233
  <div class="avatar-ring">
234
234
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=Ashley-assistant&backgroundColor=fde68a&radius=50" width="96" height="96" alt="Ashley-assistant avatar" style="border-radius:50%;">
235
235
  </div>
236
- <div class="role-chip">AI Executive Assistant</div>
236
+ <div class="role-chip">Executive Assistant</div>
237
237
  <h1>Your calendar cleared.<br>Your decisions <span>ready</span>.</h1>
238
238
  <p>Your calendar cleared. Your decisions ready. Your meetings worth attending.</p>
239
239
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AUDITya - AI Banking Auditor - FRAIM Portfolio</title>
6
+ <title>AUDITya - Banking Auditor - FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
@@ -50,7 +50,7 @@ th { color:var(--accent); font-size:11px; text-transform:uppercase; letter-spaci
50
50
  </header>
51
51
  <section class="hero">
52
52
  <div class="avatar"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=AUDITya-banking-audit&backgroundColor=e9d5ff&radius=50" width="96" height="96" alt="AUDITya banking auditor avatar" style="border-radius:50%;"></div>
53
- <div class="chip">AI Banking Auditor</div>
53
+ <div class="chip">Banking Auditor</div>
54
54
  <h1>AUDITya reviews AI banking work with <span>evidence discipline</span>.</h1>
55
55
  <p>AUDITya audits a completed KYC run, checks whether the decision is supported by evidence, records exceptions, and produces a report that can be revisited in a future review.</p>
56
56
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>BANKe - AI Banking KYC Employee - FRAIM Portfolio</title>
6
+ <title>BANKe - Banking KYC Employee - FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
@@ -50,7 +50,7 @@ th { color:var(--accent); font-size:11px; text-transform:uppercase; letter-spaci
50
50
  </header>
51
51
  <section class="hero">
52
52
  <div class="avatar"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=BANKe-banking-kyc&backgroundColor=ccfbf1&radius=50" width="96" height="96" alt="BANKe banking KYC avatar" style="border-radius:50%;"></div>
53
- <div class="chip">AI Banking KYC Employee</div>
53
+ <div class="chip">Banking KYC Employee</div>
54
54
  <h1>BANKe turns KYC work into <span>auditable evidence</span>.</h1>
55
55
  <p>BANKe reviews consent-backed banking cases, records source evidence, makes a bounded KYC decision, and leaves receipts that a separate auditor can inspect later.</p>
56
56
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>BeZa · AI Business Strategist · FRAIM Portfolio</title>
6
+ <title>BeZa · Business Strategist · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -324,7 +324,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
324
324
  <div class="avatar-ring">
325
325
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=BEZA-strategist&backgroundColor=c7d2fe&radius=50" width="96" height="96" alt="BEZA-strategist avatar" style="border-radius:50%;">
326
326
  </div>
327
- <div class="role-chip">AI Business Strategist</div>
327
+ <div class="role-chip">Business Strategist</div>
328
328
  <h1>Validates the idea. Prices the product.<br>Builds the <span>plan</span>. Ships the deck.</h1>
329
329
  <p>BeZa pressure-tests early ideas in 24 hours, turns gut-feel pricing into a data-backed structure, and writes the business plan your first investor meeting actually needs — without the 40-page consulting deliverable.</p>
330
330
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>CAREEna | AI Career Coach | FRAIM Portfolio</title>
6
+ <title>CAREEna | Career Coach | FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
@@ -349,7 +349,7 @@ body {
349
349
  <section class="hero">
350
350
  <div class="hero-grid">
351
351
  <div class="hero-panel">
352
- <div class="hero-chip">AI Career Coach</div>
352
+ <div class="hero-chip">Career Coach</div>
353
353
  <h1>Land the role with stronger applications, sharper interviews, and better timing.</h1>
354
354
  <p>CAREEna helps candidates turn a loose job search into a disciplined campaign: better-targeted openings, tighter application packages, stronger networking moves, and interview prep grounded in the actual company and role.</p>
355
355
  <div class="hero-metrics">
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>CaSey · AI Customer Success + Support · FRAIM Portfolio</title>
6
+ <title>CaSey · Customer Success + Support · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -254,7 +254,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
254
254
  <div class="avatar-ring">
255
255
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=CASEY-cx&backgroundColor=a5f3fc&radius=50" width="96" height="96" alt="CASEY-cx avatar" style="border-radius:50%;">
256
256
  </div>
257
- <div class="role-chip">AI Customer Success + Support</div>
257
+ <div class="role-chip">Customer Success + Support</div>
258
258
  <h1>Customers stay.<br><span>Issues close.</span> Health scores rise.</h1>
259
259
  <p>CaSey monitors account health signals, triages support queues, and runs survey campaigns that customers actually respond to — so churn stays low and your team stays focused.</p>
260
260
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>CELiA · AI Legal Counsel · FRAIM Portfolio</title>
6
+ <title>CELiA · Legal Counsel · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -233,7 +233,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
233
233
  <div class="avatar-ring">
234
234
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=CELA-legal&backgroundColor=cbd5e1&radius=50" width="96" height="96" alt="CELA-legal avatar" style="border-radius:50%;">
235
235
  </div>
236
- <div class="role-chip">AI Legal Counsel</div>
236
+ <div class="role-chip">Legal Counsel</div>
237
237
  <h1>Contracts reviewed.<br><span>IP protected.</span> Compliance filed.</h1>
238
238
  <p>CELiA reviews contracts for hidden risk, drafts multi-party NDAs, and files provisional patents — so your legal work gets done before the deadline, not after.</p>
239
239
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>DEIdre · AI Inclusion Leader · FRAIM Portfolio</title>
6
+ <title>DEIdre · Inclusion Leader · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -256,7 +256,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
256
256
  <div class="avatar-ring">
257
257
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=DEIDRE-inclusion-leader&backgroundColor=e9d5ff&radius=50" width="96" height="96" alt="DEIDRE-inclusion-leader avatar" style="border-radius:50%;">
258
258
  </div>
259
- <div class="role-chip">AI Inclusion Leader</div>
259
+ <div class="role-chip">Inclusion Leader</div>
260
260
  <h1>Data-driven inclusion.<br><span>Policies that work.</span> Teams that stay.</h1>
261
261
  <p>DEIdre finds the process gaps nobody measured, builds onboarding toolkits that cut early attrition, and audits hiring algorithms for disparate impact — before they become an equity and inclusion issue.</p>
262
262
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>HaRi · AI HR Manager · FRAIM Portfolio</title>
6
+ <title>HaRi · HR Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -195,7 +195,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
195
195
  <div class="avatar-ring">
196
196
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=HARI-hr&backgroundColor=ccfbf1&radius=50" width="96" height="96" alt="HARI-hr avatar" style="border-radius:50%;">
197
197
  </div>
198
- <div class="role-chip">AI HR Manager</div>
198
+ <div class="role-chip">HR Manager</div>
199
199
  <h1>Onboards fast. Reviews fairly.<br>Keeps the <span>team whole</span>.</h1>
200
200
  <p>HaRi handles the full HR lifecycle: structured onboarding that actually sticks, performance reviews that develop people, and benefits analysis that saves real money.</p>
201
201
  </section>
@@ -129,13 +129,13 @@ body { font-family: 'Inter', -apple-system, sans-serif; background: var(--bg); c
129
129
  </div>
130
130
  <div class="employee-grid">
131
131
 
132
- <!-- AIda -->
132
+ <!-- AIDa -->
133
133
  <div class="emp-card" style="cursor:pointer;">
134
134
  <div class="emp-card-top">
135
- <div class="emp-avatar" style="background:linear-gradient(135deg,#4f46e5,#06b6d4,#10b981);"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=AIda-ai-engineer&backgroundColor=c7d2fe&radius=50" width="56" height="56" alt="aida" style="border-radius:50%;"></div>
135
+ <div class="emp-avatar" style="background:linear-gradient(135deg,#4f46e5,#06b6d4,#10b981);"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=AIDa-ai-developer&backgroundColor=c7d2fe&radius=50" width="56" height="56" alt="aida" style="border-radius:50%;"></div>
136
136
  <div class="emp-info">
137
- <div class="emp-role" style="color:#4f46e5;">AI Engineer</div>
138
- <div class="emp-name">AIda</div>
137
+ <div class="emp-role" style="color:#4f46e5;">AI Developer</div>
138
+ <div class="emp-name">AIDa</div>
139
139
  <div class="emp-tagline">Agents that work. Evals that prove it.</div>
140
140
  </div>
141
141
  </div>
@@ -640,7 +640,7 @@ body { font-family: 'Inter', -apple-system, sans-serif; background: var(--bg); c
640
640
  <div class="emp-card-top">
641
641
  <div class="emp-avatar" style="background:linear-gradient(135deg,#10b981,#0ea5e9,#6366f1);"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=MAESTRO-founder-mode&backgroundColor=fde68a&radius=50" width="56" height="56" alt="maestro" style="border-radius:50%;"></div>
642
642
  <div class="emp-info">
643
- <div class="emp-role" style="color:#10b981;">Full-Brained AI Employee</div>
643
+ <div class="emp-role" style="color:#10b981;">Full-Brained Employee</div>
644
644
  <div class="emp-name">MAESTRO</div>
645
645
  <div class="emp-tagline">Every FRAIM skill. Every FRAIM job. One hire.</div>
646
646
  </div>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>MAESTRO · Full-Brained AI Employee · FRAIM Portfolio</title>
6
+ <title>MAESTRO · Full-Brained Employee · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -176,7 +176,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
176
176
  <div class="avatar-ring">
177
177
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=MAESTRO-founder-mode&backgroundColor=fde68a&radius=50" width="96" height="96" alt="MAESTRO-founder-mode avatar" style="border-radius:50%;">
178
178
  </div>
179
- <div class="role-chip">Full-Brained AI Employee</div>
179
+ <div class="role-chip">Full-Brained Employee</div>
180
180
  <h1>Every FRAIM skill.<br>Every FRAIM job. <span>One hire.</span></h1>
181
181
  <p>Every FRAIM skill. Every FRAIM job. One hire.</p>
182
182
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>MANdy · AI Manager · FRAIM Portfolio</title>
6
+ <title>MANdy · Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -204,7 +204,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
204
204
  <div class="avatar-ring">
205
205
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=MANDY-manager&backgroundColor=ede9fe&radius=50" width="96" height="96" alt="MANDY-manager avatar" style="border-radius:50%;">
206
206
  </div>
207
- <div class="role-chip">AI Manager</div>
207
+ <div class="role-chip">Manager</div>
208
208
  <h1>Orchestrates the team.<br>Delivers the <span>result</span>.</h1>
209
209
  <p>Orchestrates the team. Delivers the result. Asks for nothing in return.</p>
210
210
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>MONa · AI Finance Manager · FRAIM Portfolio</title>
6
+ <title>MONa · Finance Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -279,7 +279,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
279
279
  <div class="avatar-ring">
280
280
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=MONA-finance-manager&backgroundColor=d1fae5&radius=50" width="96" height="96" alt="MONa finance manager avatar" style="border-radius:50%;">
281
281
  </div>
282
- <div class="role-chip">AI Finance Manager</div>
282
+ <div class="role-chip">Finance Manager</div>
283
283
  <h1>Financial clarity. Fast.<br>Models that <span>drive decisions</span>.</h1>
284
284
  <p>MONa builds three-statement models without a consultant, runs FP&amp;A forecasts with driver-based scenarios, and delivers monthly close commentary that helps your board understand what actually happened and why.</p>
285
285
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>PaM · AI Product Manager · FRAIM Portfolio</title>
6
+ <title>PaM · Product Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
@@ -443,7 +443,7 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
443
443
  <div class="avatar-ring">
444
444
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=PAM-product&backgroundColor=ddd6fe&radius=50" width="96" height="96" alt="PAM-product avatar" style="border-radius:50%;">
445
445
  </div>
446
- <div class="role-chip">AI Product Manager</div>
446
+ <div class="role-chip">Product Manager</div>
447
447
  <h1>Specs that ship,<br>not <span>slide decks</span></h1>
448
448
  <p>PaM turns vague ideas into traceable requirements, phased roadmaps, and acceptance criteria that engineers can execute on — without ambiguity, without meetings.</p>
449
449
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>PROCella · AI Procurement Manager · FRAIM Portfolio</title>
6
+ <title>PROCella · Procurement Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -69,7 +69,7 @@ code,.mono { font-family:'JetBrains Mono',monospace; }
69
69
  </header>
70
70
  <section class="hero">
71
71
  <div class="avatar-ring"><img src="https://api.dicebear.com/9.x/notionists/svg?seed=PROCELLA-procurement&backgroundColor=ccfbf1&radius=50" width="96" height="96" alt="PROCella procurement manager avatar"></div>
72
- <div class="role-chip">AI Procurement Manager</div>
72
+ <div class="role-chip">Procurement Manager</div>
73
73
  <h1>PROCella makes supplier decisions <span>defensible</span>.</h1>
74
74
  <p>PROCella frames procurement strategy, builds qualified supplier options, turns RFx packages into comparable responses, and protects the buyer's leverage through approval and acceptance gates.</p>
75
75
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>QAsm · AI QA Engineer · FRAIM Portfolio</title>
6
+ <title>QAsm · QA Engineer · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -254,7 +254,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
254
254
  <div class="avatar-ring">
255
255
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=QASM-quality&backgroundColor=a7f3d0&radius=50" width="96" height="96" alt="QASM-quality avatar" style="border-radius:50%;">
256
256
  </div>
257
- <div class="role-chip">AI QA Engineer</div>
257
+ <div class="role-chip">QA Engineer</div>
258
258
  <h1>If it can break,<br>I <span>find it</span></h1>
259
259
  <p>If I find it, it gets fixed before you ship.</p>
260
260
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>RECardo · AI Recruiter · FRAIM Portfolio</title>
6
+ <title>RECardo · Recruiter · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -180,7 +180,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
180
180
  <div class="avatar-ring">
181
181
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=RICARDO-recruiter&backgroundColor=ede9fe&radius=50" width="96" height="96" alt="RICARDO-recruiter avatar" style="border-radius:50%;">
182
182
  </div>
183
- <div class="role-chip">AI Recruiter</div>
183
+ <div class="role-chip">Recruiter</div>
184
184
  <h1>Sourced, screened, scheduled.<br>You just do the <span>interviews</span>.</h1>
185
185
  <p>RECardo runs full-cycle recruiting: sourcing candidates who actually fit, writing job posts engineers read, and coordinating interview loops without the calendar chaos.</p>
186
186
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SADE · AI Salesforce Developer · FRAIM Portfolio</title>
6
+ <title>SADE · Salesforce Developer · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -230,7 +230,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
230
230
  <div class="avatar-ring">
231
231
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=SADE-salesforce&backgroundColor=bae6fd&radius=50" width="96" height="96" alt="SADE-salesforce avatar" style="border-radius:50%;">
232
232
  </div>
233
- <div class="role-chip">AI Salesforce Developer</div>
233
+ <div class="role-chip">Salesforce Developer</div>
234
234
  <h1>Clean orgs.<br><span>Automations</span> that actually run.</h1>
235
235
  <p>Reports that tell the truth.</p>
236
236
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SAM · AI Sales Account Manager · FRAIM Portfolio</title>
6
+ <title>SAM · Sales Account Manager · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -283,7 +283,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
283
283
  <div class="avatar-ring">
284
284
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=SAM-sales-account&backgroundColor=d1fae5&radius=50" width="96" height="96" alt="SAM-sales-account avatar" style="border-radius:50%;">
285
285
  </div>
286
- <div class="role-chip">AI Sales Account Manager</div>
286
+ <div class="role-chip">Sales Account Manager</div>
287
287
  <h1>More pipeline. More signal.<br>More <span>deals closed</span>.</h1>
288
288
  <p>SAM finds qualified prospects without a database subscription, spots at-risk accounts before they churn, and delivers pipeline reviews that free your VP of Sales from 90 minutes of spreadsheet work every Friday.</p>
289
289
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SEChar | AI Security Engineer | FRAIM Portfolio</title>
6
+ <title>SEChar | Security Engineer | FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
@@ -334,7 +334,7 @@ h1 {
334
334
  <section class="hero">
335
335
  <div class="hero-grid">
336
336
  <div class="panel">
337
- <div class="chip">AI Security Engineer</div>
337
+ <div class="chip">Security Engineer</div>
338
338
  <h1>Setup the baseline. Run the queue. Clear the risk.</h1>
339
339
  <p>SEChar sets the launch baseline, keeps the findings queue coherent, and still handles the diff-scoped reviews and remediation calls teams expect from an applied security partner.</p>
340
340
  <div class="hero-metrics">
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SREya · AI Site Reliability Engineer · FRAIM Portfolio</title>
6
+ <title>SREya · Site Reliability Engineer · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -276,7 +276,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
276
276
  <div class="avatar-ring">
277
277
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=SREYA-site-reliability&backgroundColor=dbeafe&radius=50" width="96" height="96" alt="SREya site reliability engineer avatar" style="border-radius:50%;">
278
278
  </div>
279
- <div class="role-chip">AI Site Reliability Engineer</div>
279
+ <div class="role-chip">Site Reliability Engineer</div>
280
280
  <h1>SLOs that reflect user pain.<br>Incidents <span>resolved, not survived</span>.</h1>
281
281
  <p>SREya designs error budgets before you need them, runs structured incident command that cuts MTTR in half, and delivers quarterly reliability reviews that give your on-call team a roadmap instead of a burnout spiral.</p>
282
282
  </section>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SWEn · AI Software Engineer · FRAIM Portfolio</title>
6
+ <title>SWEn · Software Engineer · FRAIM Portfolio</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
@@ -254,7 +254,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
254
254
  <div class="avatar-ring">
255
255
  <img src="https://api.dicebear.com/9.x/notionists/svg?seed=SWEN-engineer&backgroundColor=bfdbfe&radius=50" width="96" height="96" alt="SWEN-engineer avatar" style="border-radius:50%;">
256
256
  </div>
257
- <div class="role-chip">AI Software Engineer</div>
257
+ <div class="role-chip">Software Engineer</div>
258
258
  <h1>Ships clean code,<br>not <span>promises</span></h1>
259
259
  <p>SWEn delivers production-ready implementations: type-safe APIs, test coverage, real artifacts in the codebase — not prototype code masquerading as ship-ready work.</p>
260
260
  </section>
@@ -314,13 +314,13 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
314
314
  <span class="t-kw">export const</span> <span class="t-val">PERSONA_HIRE_CATALOG</span> <span class="t-op">=</span> {
315
315
  huxley<span class="t-op">:</span> {
316
316
  displayName<span class="t-op">:</span> <span class="t-str">'hUXley'</span>,
317
- role<span class="t-op">:</span> <span class="t-str">'AI UX / Brand Designer'</span>,
317
+ role<span class="t-op">:</span> <span class="t-str">'UX / Brand Designer'</span>,
318
318
  jobPriceCents<span class="t-op">:</span> <span class="t-num">14900</span>,
319
319
  fulltimePriceCents<span class="t-op">:</span> <span class="t-num">54900</span>,
320
320
  },
321
321
  pam<span class="t-op">:</span> {
322
322
  displayName<span class="t-op">:</span> <span class="t-str">'PaM'</span>,
323
- role<span class="t-op">:</span> <span class="t-str">'AI Product Manager'</span>,
323
+ role<span class="t-op">:</span> <span class="t-str">'Product Manager'</span>,
324
324
  jobPriceCents<span class="t-op">:</span> <span class="t-num">7900</span>,
325
325
  fulltimePriceCents<span class="t-op">:</span> <span class="t-num">49900</span>,
326
326
  },