@indigoai-us/hq-cli 5.238.0 → 5.239.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,17 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.239.0] — 2026-09-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `hq core checkpoint` can skip a knowledge link to a concept entity whose
|
|
10
|
+
name is also the name of an entity of another type, such as a concept
|
|
11
|
+
`hq-secrets` beside a project `HQ Secrets`. The report lists the skipped
|
|
12
|
+
link as rejected with reason `ambiguous_type`. Signal and session inputs,
|
|
13
|
+
other links and new entities are unchanged. Behind the hq-flags flag
|
|
14
|
+
`checkpoint.ontology.skip-ambiguous-concept-links`, off by default.
|
|
15
|
+
|
|
5
16
|
## [5.238.0] — 2026-09-27
|
|
6
17
|
|
|
7
18
|
### Added: Lane orphan reporting
|
|
@@ -262,6 +262,25 @@ export function applyOntologyRun(options) {
|
|
|
262
262
|
}
|
|
263
263
|
report.candidates = rawCandidates.length;
|
|
264
264
|
const index = buildEntityIndex(company.dir);
|
|
265
|
+
// checkpoint.ontology.skip-ambiguous-concept-links: canonical names held by entities of more than one type.
|
|
266
|
+
// Names compare in the non-organization form for every type (lowercase, keeps + and #, no squashing),
|
|
267
|
+
// so "C++" and "C", or "AB" and "A B", stay distinct.
|
|
268
|
+
const crossTypeKey = (name) => normalizeEntityName(name, "concept");
|
|
269
|
+
const crossTypeNames = new Set();
|
|
270
|
+
if (plan.skip_ambiguous_concept_links === true) {
|
|
271
|
+
const typesByName = new Map();
|
|
272
|
+
for (const entity of index.byRel.values()) {
|
|
273
|
+
const name = crossTypeKey(entity.canonical_name);
|
|
274
|
+
if (name === "")
|
|
275
|
+
continue;
|
|
276
|
+
const types = typesByName.get(name) ?? new Set();
|
|
277
|
+
types.add(entity.type);
|
|
278
|
+
typesByName.set(name, types);
|
|
279
|
+
}
|
|
280
|
+
for (const [name, types] of typesByName)
|
|
281
|
+
if (types.size > 1)
|
|
282
|
+
crossTypeNames.add(name);
|
|
283
|
+
}
|
|
265
284
|
const inputs = liveInputs(options.hqRoot, company, plan);
|
|
266
285
|
const blocked = new Set();
|
|
267
286
|
const updates = new Map();
|
|
@@ -313,8 +332,14 @@ export function applyOntologyRun(options) {
|
|
|
313
332
|
continue;
|
|
314
333
|
}
|
|
315
334
|
if (resolved.tier === 1 || resolved.tier === 2) {
|
|
316
|
-
report.matched += 1;
|
|
317
335
|
const linked = index.byRel.get(resolved.target);
|
|
336
|
+
if (input.kind === "knowledge" &&
|
|
337
|
+
linked.type === "concept" &&
|
|
338
|
+
crossTypeNames.has(crossTypeKey(linked.canonical_name))) {
|
|
339
|
+
note(report.rejected, "ambiguous_type");
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
report.matched += 1;
|
|
318
343
|
report.links.push({ input: candidate.input, action: "link", type: linked.type, canonical_name: linked.canonical_name, path: resolved.target });
|
|
319
344
|
if (resolved.tier === 1 && resolved.duplicates.length > 0) {
|
|
320
345
|
report.suspect_duplicates.push({ name: canonical, type: candidate.type, paths: [resolved.target, ...resolved.duplicates] });
|
|
@@ -68,6 +68,16 @@ export declare const NO_LINK_ALIASES_FLAG = "checkpoint.ontology.no-link-aliases
|
|
|
68
68
|
* the model cannot see that `John Smith` already exists.
|
|
69
69
|
*/
|
|
70
70
|
export declare const FIRST_NAME_PEOPLE_FLAG = "checkpoint.ontology.first-name-people";
|
|
71
|
+
/**
|
|
72
|
+
* A knowledge input does not link to a concept entity whose canonical name is
|
|
73
|
+
* also the canonical name of an entity of another type (`concept/hq-secrets`
|
|
74
|
+
* beside `project/hq-secrets`). The plan carries
|
|
75
|
+
* `skip_ambiguous_concept_links: true`, and apply rejects the link as
|
|
76
|
+
* `ambiguous_type`. CO-46: 34 of the 73 false positives on the knowledge
|
|
77
|
+
* fixtures were such concept links; skipping them raised precision from 0.733
|
|
78
|
+
* to 0.803 and cost recall 0.023 on a replay of six runs.
|
|
79
|
+
*/
|
|
80
|
+
export declare const SKIP_AMBIGUOUS_CONCEPT_LINKS_FLAG = "checkpoint.ontology.skip-ambiguous-concept-links";
|
|
71
81
|
export declare const PLAN_FILE = "ontology-plan.json";
|
|
72
82
|
export declare const CANDIDATES_FILE = "ontology-candidates.json";
|
|
73
83
|
export declare const REPORT_FILE = "ontology-report.json";
|
|
@@ -138,6 +148,8 @@ export interface OntologyPlan {
|
|
|
138
148
|
link_aliases?: false;
|
|
139
149
|
/** Set by checkpoint.ontology.first-name-people: apply defers a one-word person who may be an existing fuller name. */
|
|
140
150
|
first_name_people?: true;
|
|
151
|
+
/** Set by checkpoint.ontology.skip-ambiguous-concept-links: apply rejects a knowledge link to a concept whose name another type also holds. */
|
|
152
|
+
skip_ambiguous_concept_links?: true;
|
|
141
153
|
inputs: PlanInput[];
|
|
142
154
|
/** The session's summary, decisions and learnings, for the `session` input. */
|
|
143
155
|
session_text: string | null;
|
|
@@ -72,6 +72,16 @@ export const NO_LINK_ALIASES_FLAG = "checkpoint.ontology.no-link-aliases";
|
|
|
72
72
|
* the model cannot see that `John Smith` already exists.
|
|
73
73
|
*/
|
|
74
74
|
export const FIRST_NAME_PEOPLE_FLAG = "checkpoint.ontology.first-name-people";
|
|
75
|
+
/**
|
|
76
|
+
* A knowledge input does not link to a concept entity whose canonical name is
|
|
77
|
+
* also the canonical name of an entity of another type (`concept/hq-secrets`
|
|
78
|
+
* beside `project/hq-secrets`). The plan carries
|
|
79
|
+
* `skip_ambiguous_concept_links: true`, and apply rejects the link as
|
|
80
|
+
* `ambiguous_type`. CO-46: 34 of the 73 false positives on the knowledge
|
|
81
|
+
* fixtures were such concept links; skipping them raised precision from 0.733
|
|
82
|
+
* to 0.803 and cost recall 0.023 on a replay of six runs.
|
|
83
|
+
*/
|
|
84
|
+
export const SKIP_AMBIGUOUS_CONCEPT_LINKS_FLAG = "checkpoint.ontology.skip-ambiguous-concept-links";
|
|
75
85
|
export const PLAN_FILE = "ontology-plan.json";
|
|
76
86
|
export const CANDIDATES_FILE = "ontology-candidates.json";
|
|
77
87
|
export const REPORT_FILE = "ontology-report.json";
|
|
@@ -254,6 +264,7 @@ export async function planOntologyRun(options) {
|
|
|
254
264
|
const hintsOn = await options.readFlag(ENTITY_HINTS_FLAG, company);
|
|
255
265
|
const noLinkAliases = await options.readFlag(NO_LINK_ALIASES_FLAG, company);
|
|
256
266
|
const firstNamePeople = await options.readFlag(FIRST_NAME_PEOPLE_FLAG, company);
|
|
267
|
+
const skipAmbiguousConceptLinks = await options.readFlag(SKIP_AMBIGUOUS_CONCEPT_LINKS_FLAG, company);
|
|
257
268
|
const touched = sessionTouched(hqRoot, company, payload.files);
|
|
258
269
|
// A first run takes its boundary from the entity tree, so the ledger is
|
|
259
270
|
// refreshed before merge-back moves any `last_updated` forward.
|
|
@@ -368,6 +379,7 @@ export async function planOntologyRun(options) {
|
|
|
368
379
|
...(multiWriter ? { multi_writer: multiWriter } : {}),
|
|
369
380
|
...(noLinkAliases ? { link_aliases: false } : {}),
|
|
370
381
|
...(firstNamePeople ? { first_name_people: true } : {}),
|
|
382
|
+
...(skipAmbiguousConceptLinks ? { skip_ambiguous_concept_links: true } : {}),
|
|
371
383
|
inputs,
|
|
372
384
|
session_text: sessionText,
|
|
373
385
|
pending_after_run: remaining,
|