@indigoai-us/hq-cli 5.230.2 → 5.231.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.231.0] — 2026-09-27
6
+
7
+ ### Added
8
+
9
+ - Behind the off-by-default `checkpoint.ontology.first-name-people` flag, the
10
+ checkpoint ontology instructions tell the model to name a person by their
11
+ first name when neither the input nor the company's entities give more,
12
+ instead of leaving them out. With the flag on, apply also defers a one-word
13
+ person whose word starts an existing person's fuller name or alias (`John`
14
+ when `John Smith` exists), since the model cannot see the entity tree. With
15
+ the flag off the instructions and apply are unchanged.
16
+
5
17
  ## [5.230.2] — 2026-09-27
6
18
 
7
19
  ### Fixed
@@ -128,6 +128,13 @@ export declare function resolveCandidate(index: EntityIndex, type: string, canon
128
128
  * (`Chaudhry Hassaan Saleem` and `Hassaan Saleem`).
129
129
  */
130
130
  export declare function overlappingEntities(index: EntityIndex, type: string, canonical: string, aliases: string[]): string[];
131
+ /**
132
+ * Existing people a one-word person candidate may be: the word is the first
133
+ * word of their name or of one of their aliases, and that name has two words
134
+ * or more (`John` and `John Smith`). The model never sees the entity tree, so
135
+ * it cannot tell a first name that the company already holds in full.
136
+ */
137
+ export declare function firstNameOverlap(index: EntityIndex, canonical: string): string[];
131
138
  export declare function applyOntologyRun(options: ApplyOptions): ApplyReport;
132
139
  export {};
133
140
  //# sourceMappingURL=apply.d.ts.map
@@ -113,6 +113,30 @@ export function overlappingEntities(index, type, canonical, aliases) {
113
113
  }
114
114
  return [...paths].sort();
115
115
  }
116
+ /**
117
+ * Existing people a one-word person candidate may be: the word is the first
118
+ * word of their name or of one of their aliases, and that name has two words
119
+ * or more (`John` and `John Smith`). The model never sees the entity tree, so
120
+ * it cannot tell a first name that the company already holds in full.
121
+ */
122
+ export function firstNameOverlap(index, canonical) {
123
+ const words = normalizeEntityName(canonical, "person").split(" ");
124
+ if (words.length !== 1 || !words[0])
125
+ return [];
126
+ const prefix = entityKey("person", "");
127
+ const paths = new Set();
128
+ for (const map of [index.canonical, index.alias]) {
129
+ for (const [name, rels] of map) {
130
+ if (!name.startsWith(prefix))
131
+ continue;
132
+ const other = name.slice(prefix.length).split(" ");
133
+ if (other.length >= 2 && other[0] === words[0])
134
+ for (const rel of rels)
135
+ paths.add(rel);
136
+ }
137
+ }
138
+ return [...paths].sort();
139
+ }
116
140
  function readJson(file) {
117
141
  return JSON.parse(fs.readFileSync(file, "utf8"));
118
142
  }
@@ -335,6 +359,12 @@ export function applyOntologyRun(options) {
335
359
  report.suspect_duplicates.push({ name: canonical, type: candidate.type, paths: overlap });
336
360
  continue;
337
361
  }
362
+ const firstName = plan.first_name_people === true && candidate.type === "person" ? firstNameOverlap(index, canonical) : [];
363
+ if (firstName.length > 0) {
364
+ note(report.deferred, "suspect_duplicate");
365
+ report.suspect_duplicates.push({ name: canonical, type: candidate.type, paths: firstName });
366
+ continue;
367
+ }
338
368
  // Tier 5: create.
339
369
  if (candidate.confidence < MIN_CREATE_CONFIDENCE) {
340
370
  note(report.rejected, "low_confidence");
@@ -48,6 +48,17 @@ export declare const ENTITY_HINTS_FLAG = "checkpoint.ontology.entity-hints";
48
48
  * hinted runs).
49
49
  */
50
50
  export declare const NO_LINK_ALIASES_FLAG = "checkpoint.ontology.no-link-aliases";
51
+ /**
52
+ * A person the input and the company's entities give only a first name for is
53
+ * named by that first name instead of being left out. CO-44: on the CO-41
54
+ * grok-4.6 runs the model read "not a first name alone" as "skip them", and
55
+ * dropped people such as Amir and Sebastian, whose own entities carry only a
56
+ * first name. People were 24 of the 138 missed gold entities over three runs.
57
+ * The plan carries `first_name_people: true`, and apply then defers a one-word
58
+ * person whose word starts an existing person's fuller name or alias, since
59
+ * the model cannot see that `John Smith` already exists.
60
+ */
61
+ export declare const FIRST_NAME_PEOPLE_FLAG = "checkpoint.ontology.first-name-people";
51
62
  export declare const PLAN_FILE = "ontology-plan.json";
52
63
  export declare const CANDIDATES_FILE = "ontology-candidates.json";
53
64
  export declare const REPORT_FILE = "ontology-report.json";
@@ -116,6 +127,8 @@ export interface OntologyPlan {
116
127
  multi_writer?: MultiWriterStart;
117
128
  /** Present, as false, only when `checkpoint.ontology.no-link-aliases` was on for this plan. */
118
129
  link_aliases?: false;
130
+ /** Set by checkpoint.ontology.first-name-people: apply defers a one-word person who may be an existing fuller name. */
131
+ first_name_people?: true;
119
132
  inputs: PlanInput[];
120
133
  /** The session's summary, decisions and learnings, for the `session` input. */
121
134
  session_text: string | null;
@@ -160,6 +173,8 @@ export type PlanOutcome = {
160
173
  };
161
174
  export declare const READ_PATH_INSTRUCTION = "When an input has read_path, read that file (relative to the run directory) instead of path, with the same line range. It is the same text with an older annotator's entity lists and entity links removed.";
162
175
  export declare const ENTITY_HINTS_INSTRUCTIONS: string[];
176
+ export declare const PERSON_NAME_INSTRUCTION = "Name a person by the full name the input or the company's entities give, not a first name alone.";
177
+ export declare const FIRST_NAME_PEOPLE_INSTRUCTION = "Name a person by the full name the input or the company's entities give. When neither gives more than a first name, name the person by that first name; do not leave them out.";
163
178
  export declare function ledgerPath(hqRoot: string, company: OntologyCompany): string;
164
179
  export declare function readLedger(hqRoot: string, company: OntologyCompany): Ledger | null;
165
180
  export declare function writeLedger(hqRoot: string, company: OntologyCompany, ledger: Ledger): void;
@@ -52,6 +52,17 @@ export const ENTITY_HINTS_FLAG = "checkpoint.ontology.entity-hints";
52
52
  * hinted runs).
53
53
  */
54
54
  export const NO_LINK_ALIASES_FLAG = "checkpoint.ontology.no-link-aliases";
55
+ /**
56
+ * A person the input and the company's entities give only a first name for is
57
+ * named by that first name instead of being left out. CO-44: on the CO-41
58
+ * grok-4.6 runs the model read "not a first name alone" as "skip them", and
59
+ * dropped people such as Amir and Sebastian, whose own entities carry only a
60
+ * first name. People were 24 of the 138 missed gold entities over three runs.
61
+ * The plan carries `first_name_people: true`, and apply then defers a one-word
62
+ * person whose word starts an existing person's fuller name or alias, since
63
+ * the model cannot see that `John Smith` already exists.
64
+ */
65
+ export const FIRST_NAME_PEOPLE_FLAG = "checkpoint.ontology.first-name-people";
55
66
  export const PLAN_FILE = "ontology-plan.json";
56
67
  export const CANDIDATES_FILE = "ontology-candidates.json";
57
68
  export const REPORT_FILE = "ontology-report.json";
@@ -68,11 +79,13 @@ export const ENTITY_HINTS_INSTRUCTIONS = [
68
79
  "A knowledge input's known_entities lists entities that already exist in the company and whose names appear in its text. When the input refers to one of them, under that name or another, use that entity's name and type exactly and do not name a new entity for it.",
69
80
  "Skip rows of a glossary or translation table, file and directory paths, and names built from tags or slugs.",
70
81
  ];
82
+ export const PERSON_NAME_INSTRUCTION = "Name a person by the full name the input or the company's entities give, not a first name alone.";
83
+ export const FIRST_NAME_PEOPLE_INSTRUCTION = "Name a person by the full name the input or the company's entities give. When neither gives more than a first name, name the person by that first name; do not leave them out.";
71
84
  const CANDIDATE_INSTRUCTIONS = [
72
85
  `Write ${CANDIDATES_FILE} in the run directory as {"schema":"${CANDIDATES_SCHEMA}","candidates":[...]} and nothing else.`,
73
86
  "Each candidate: {input, type, name, aliases, confidence, evidence}. input is one of this plan's input ids; type is person, project, company or concept; name is the entity's full proper name; aliases are other names the input uses for it (at most 5); confidence is 0 to 1; evidence is a short quote from the input.",
74
87
  "Read only the files and line ranges this plan lists. For a signal, read its body and name the entities in missing_refs if the signal supports them.",
75
- "Name the specific people, projects, products, companies and named concepts that the input says something about. That includes the company that owns this knowledge and its own products when the input describes them. Name a third-party tool, vendor or service only when a section of the input is about it; skip ones that appear in a list, a stack summary or a passing mention. Skip generic words, file names and headings. Name a person by the full name the input or the company's entities give, not a first name alone.",
88
+ "Name the specific people, projects, products, companies and named concepts that the input says something about. That includes the company that owns this knowledge and its own products when the input describes them. Name a third-party tool, vendor or service only when a section of the input is about it; skip ones that appear in a list, a stack summary or a passing mention. Skip generic words, file names and headings.",
76
89
  "For the session input (its text is session_text in this plan), name only entities that already exist in the company and that the session did work on. Session candidates are recorded as links, never created.",
77
90
  "Do not create, edit, move or delete anything under ontology/, signals/ or sources/ yourself.",
78
91
  ];
@@ -229,6 +242,7 @@ export async function planOntologyRun(options) {
229
242
  const multiWriterOn = await options.readFlag(MULTI_WRITER_FLAG, company);
230
243
  const hintsOn = await options.readFlag(ENTITY_HINTS_FLAG, company);
231
244
  const noLinkAliases = await options.readFlag(NO_LINK_ALIASES_FLAG, company);
245
+ const firstNamePeople = await options.readFlag(FIRST_NAME_PEOPLE_FLAG, company);
232
246
  const touched = sessionTouched(hqRoot, company, payload.files);
233
247
  // A first run takes its boundary from the entity tree, so the ledger is
234
248
  // refreshed before merge-back moves any `last_updated` forward.
@@ -342,6 +356,7 @@ export async function planOntologyRun(options) {
342
356
  : {}),
343
357
  ...(multiWriter ? { multi_writer: multiWriter } : {}),
344
358
  ...(noLinkAliases ? { link_aliases: false } : {}),
359
+ ...(firstNamePeople ? { first_name_people: true } : {}),
345
360
  inputs,
346
361
  session_text: sessionText,
347
362
  pending_after_run: remaining,
@@ -355,7 +370,7 @@ export async function planOntologyRun(options) {
355
370
  instructions: [
356
371
  ...CANDIDATE_INSTRUCTIONS.slice(0, 3),
357
372
  ...(inputs.some((input) => input.read_path) ? [READ_PATH_INSTRUCTION] : []),
358
- CANDIDATE_INSTRUCTIONS[3],
373
+ `${CANDIDATE_INSTRUCTIONS[3]} ${firstNamePeople ? FIRST_NAME_PEOPLE_INSTRUCTION : PERSON_NAME_INSTRUCTION}`,
359
374
  ...(inputs.some((input) => input.known_entities) ? ENTITY_HINTS_INSTRUCTIONS : []),
360
375
  ...CANDIDATE_INSTRUCTIONS.slice(4),
361
376
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.230.2",
3
+ "version": "5.231.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {