@indigoai-us/hq-cli 5.263.0 → 5.265.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 +24 -0
- package/dist/command-catalog.generated.d.ts +16 -0
- package/dist/command-catalog.generated.js +21 -0
- package/dist/commands/lanes-kpis.d.ts +11 -0
- package/dist/commands/lanes-kpis.js +34 -0
- package/dist/commands/lanes-watch.js +2 -1
- package/dist/commands/lanes.js +12 -0
- package/dist/lib/checkpoint-ontology/plan.d.ts +0 -11
- package/dist/lib/checkpoint-ontology/plan.js +0 -28
- package/dist/lib/lanes/config.d.ts +2 -0
- package/dist/lib/lanes/config.js +4 -0
- package/dist/lib/lanes/keep-alive.d.ts +2 -2
- package/dist/lib/lanes/keep-alive.js +9 -6
- package/dist/lib/lanes/kr-freshness.d.ts +76 -0
- package/dist/lib/lanes/kr-freshness.js +412 -0
- package/dist/lib/lanes/lane-company.d.ts +9 -0
- package/dist/lib/lanes/lane-company.js +24 -0
- package/dist/lib/lanes/reconcile.js +57 -6
- package/dist/lib/lanes/types.d.ts +20 -1
- package/dist/lib/lanes/types.js +1 -1
- package/dist/lib/lanes/watcher.d.ts +2 -0
- package/dist/lib/lanes/watcher.js +70 -1
- package/package.json +1 -1
- package/dist/lib/checkpoint-ontology/hints.d.ts +0 -41
- package/dist/lib/checkpoint-ontology/hints.js +0 -146
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.265.0] — 2026-09-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- The `lanes.kr-freshness` flag tracks each manager KPI in a runtime-owned
|
|
10
|
+
ledger and queues one corrective resume for each stalled KPI set. The
|
|
11
|
+
freshness window defaults to six hours and can be set with
|
|
12
|
+
`kr_freshness_hours` in the lanes config.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Reconcile resolves a missing lane company for keep-alive and supersession
|
|
17
|
+
flag reads, and watch applies the same resolution to keep-alive checks.
|
|
18
|
+
Unusable project ownership remains unresolved; reconcile reports
|
|
19
|
+
`keep_alive_company_unresolved` or `keep_alive_flag_off` instead of silently
|
|
20
|
+
skipping those candidates.
|
|
21
|
+
|
|
22
|
+
## [5.264.0] — 2026-09-28
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
|
|
26
|
+
- The `checkpoint.ontology.entity-hints` flag and its per-input `known_entities`
|
|
27
|
+
list. It was never turned on outside measurement runs.
|
|
28
|
+
|
|
5
29
|
## [5.263.0] — 2026-09-28
|
|
6
30
|
|
|
7
31
|
### Fixed
|
|
@@ -7537,6 +7537,22 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
7537
7537
|
}];
|
|
7538
7538
|
readonly subcommands: readonly [];
|
|
7539
7539
|
}];
|
|
7540
|
+
}, {
|
|
7541
|
+
readonly name: "kpis";
|
|
7542
|
+
readonly description: "Show runtime freshness for a manager lane's key results";
|
|
7543
|
+
readonly aliases: readonly [];
|
|
7544
|
+
readonly hidden: false;
|
|
7545
|
+
readonly usage: "[options] <lane>";
|
|
7546
|
+
readonly arguments: readonly [{
|
|
7547
|
+
readonly name: "lane";
|
|
7548
|
+
readonly required: true;
|
|
7549
|
+
readonly variadic: false;
|
|
7550
|
+
}];
|
|
7551
|
+
readonly options: readonly [{
|
|
7552
|
+
readonly flags: "--json";
|
|
7553
|
+
readonly description: "Print the KR freshness report as JSON";
|
|
7554
|
+
}];
|
|
7555
|
+
readonly subcommands: readonly [];
|
|
7540
7556
|
}, {
|
|
7541
7557
|
readonly name: "create";
|
|
7542
7558
|
readonly description: "Register a lane, run admission, and return immediately";
|
|
@@ -9742,6 +9742,27 @@ export const COMMAND_CATALOG = [
|
|
|
9742
9742
|
}
|
|
9743
9743
|
]
|
|
9744
9744
|
},
|
|
9745
|
+
{
|
|
9746
|
+
"name": "kpis",
|
|
9747
|
+
"description": "Show runtime freshness for a manager lane's key results",
|
|
9748
|
+
"aliases": [],
|
|
9749
|
+
"hidden": false,
|
|
9750
|
+
"usage": "[options] <lane>",
|
|
9751
|
+
"arguments": [
|
|
9752
|
+
{
|
|
9753
|
+
"name": "lane",
|
|
9754
|
+
"required": true,
|
|
9755
|
+
"variadic": false
|
|
9756
|
+
}
|
|
9757
|
+
],
|
|
9758
|
+
"options": [
|
|
9759
|
+
{
|
|
9760
|
+
"flags": "--json",
|
|
9761
|
+
"description": "Print the KR freshness report as JSON"
|
|
9762
|
+
}
|
|
9763
|
+
],
|
|
9764
|
+
"subcommands": []
|
|
9765
|
+
},
|
|
9745
9766
|
{
|
|
9746
9767
|
"name": "create",
|
|
9747
9768
|
"description": "Register a lane, run admission, and return immediately",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export interface LaneKpisCommandDeps {
|
|
3
|
+
hqRoot: () => string;
|
|
4
|
+
now: () => Date;
|
|
5
|
+
wrap: WrapHandler;
|
|
6
|
+
}
|
|
7
|
+
type WrapHandler = <Args extends unknown[]>(action: (...args: Args) => Promise<void>) => (...args: Args) => Promise<void>;
|
|
8
|
+
/** Register the operator report command without depending on the large lanes registrar. */
|
|
9
|
+
export declare function registerLaneKpisCommand(parent: Command, deps: LaneKpisCommandDeps): void;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=lanes-kpis.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readKrFreshnessReport } from "../lib/lanes/kr-freshness.js";
|
|
2
|
+
/** Register the operator report command without depending on the large lanes registrar. */
|
|
3
|
+
export function registerLaneKpisCommand(parent, deps) {
|
|
4
|
+
parent
|
|
5
|
+
.command("kpis")
|
|
6
|
+
.description("Show runtime freshness for a manager lane's key results")
|
|
7
|
+
.argument("<lane>")
|
|
8
|
+
.option("--json", "Print the KR freshness report as JSON")
|
|
9
|
+
.action(deps.wrap(async (laneId, options) => {
|
|
10
|
+
const report = readKrFreshnessReport(deps.hqRoot(), laneId, deps.now().getTime());
|
|
11
|
+
const result = {
|
|
12
|
+
ok: true,
|
|
13
|
+
action: "kpis",
|
|
14
|
+
lane_id: laneId,
|
|
15
|
+
ledger_available: report.available,
|
|
16
|
+
ledger_path: report.ledger_path,
|
|
17
|
+
kr_freshness_hours: report.kr_freshness_hours,
|
|
18
|
+
kpis: report.kpis,
|
|
19
|
+
};
|
|
20
|
+
if (options.json) {
|
|
21
|
+
console.log(JSON.stringify(result));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!report.available) {
|
|
25
|
+
console.log(`No KR freshness ledger exists for ${laneId}. Expected ${report.ledger_path}.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log(`KR freshness for ${laneId} (window ${report.kr_freshness_hours}h):`);
|
|
29
|
+
for (const kpi of report.kpis) {
|
|
30
|
+
console.log(`${kpi.name}: ${JSON.stringify(kpi.value)} — ${kpi.verdict}; measured ${kpi.measured_at}; value changed ${kpi.value_changed_at}`);
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=lanes-kpis.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { accountStatus, coveredLaneIds, loadLanesConfig, MAX_WATCHED_LANES, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_UNCOVERED_EXIT_CODE, monitorReminderText, runLaneWatch, } from "../lib/lanes/index.js";
|
|
2
2
|
import { LEAD_LANE_KEEP_ALIVE_FLAG } from "../lib/lanes/keep-alive.js";
|
|
3
|
+
import { resolveLaneCompany } from "../lib/lanes/lane-company.js";
|
|
3
4
|
import { readLanesRegistryFlag } from "../lib/lanes/registry-flag.js";
|
|
4
5
|
import { isLanesError, LanesError } from "../lib/lanes/errors.js";
|
|
5
6
|
import { LANE_WAIT_INVALID_INPUT_EXIT_CODE, LANE_WAIT_TIMEOUT_EXIT_CODE, runLaneWait, } from "../lib/lanes/wait.js";
|
|
@@ -46,7 +47,7 @@ export function createLaneWatchHandlers(deps) {
|
|
|
46
47
|
intervalMs: rawInterval,
|
|
47
48
|
sleep: ctx.sleep,
|
|
48
49
|
keepAliveEnabled: (lane) => readLanesRegistryFlag(LEAD_LANE_KEEP_ALIVE_FLAG, {
|
|
49
|
-
company: lane.company,
|
|
50
|
+
company: resolveLaneCompany(hqRoot, lane).company ?? undefined,
|
|
50
51
|
env: ctx.env,
|
|
51
52
|
}),
|
|
52
53
|
readAccountStatuses: async (lanes) => {
|
package/dist/commands/lanes.js
CHANGED
|
@@ -18,6 +18,7 @@ import { createLaneResumeHandlers } from "./lanes-resume.js";
|
|
|
18
18
|
import { createLaneWatchHandlers } from "./lanes-watch.js";
|
|
19
19
|
export { resolveAnswerChoice } from "./lanes-questions.js";
|
|
20
20
|
import { registerOutpostPrunerCommand } from "./outpost-pruner.js";
|
|
21
|
+
import { registerLaneKpisCommand } from "./lanes-kpis.js";
|
|
21
22
|
import { registerLaneChecksCommand } from "./lanes-checks.js";
|
|
22
23
|
import { registerLaneReportCommands } from "./lanes-report.js";
|
|
23
24
|
import { registerLaneTrackerImportCommand } from "./lanes-import.js";
|
|
@@ -50,6 +51,7 @@ import { effectiveAccountHome } from "../lib/lanes/account-home.js";
|
|
|
50
51
|
import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, aliveDirectChildren, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readLane, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
|
|
51
52
|
import { activeLaneStories, laneStories, laneStory, storyWarning, } from "../lib/lanes/stories.js";
|
|
52
53
|
import { resolveLaneKeepAlive } from "../lib/lanes/profile.js";
|
|
54
|
+
import { resolveLaneCompany } from "../lib/lanes/lane-company.js";
|
|
53
55
|
import { doneKeepAliveVerdict, hasPendingKeepAliveWork, keepAliveExclusion, LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, loadRetiredLaneIds, } from "../lib/lanes/keep-alive.js";
|
|
54
56
|
import { questionBodyAbsPath, resolveQuestionCompanyWithFallback, resolveProjectQuestionCompany, } from "../lib/lanes/questions.js";
|
|
55
57
|
import { assertQuestionBodySecretSafe } from "../lib/lanes/questions.js";
|
|
@@ -60,6 +62,7 @@ import { loadQuotaState, quotaBlockFor } from "../lib/lanes/quota.js";
|
|
|
60
62
|
import { SESSION_MOVE_REASON } from "../lib/lanes/move-account.js";
|
|
61
63
|
import { managerStatusGateEnabledForLane, resolveManagerStatusGateForLane, } from "../lib/lanes/manager-status-gate.js";
|
|
62
64
|
import { blockerFreshnessFingerprint, resolveBlockerFreshnessForLane, } from "../lib/lanes/blocker-freshness.js";
|
|
65
|
+
import { resolveKrFreshnessForShow } from "../lib/lanes/kr-freshness.js";
|
|
63
66
|
import { ensureSessionHome } from "../lib/lanes/session-relink.js";
|
|
64
67
|
import { defaultProbe, validateProfileLaneModel, validateLaneModel, } from "../lib/lanes/models.js";
|
|
65
68
|
import { parseCliModel, refuseOutpostSelfTarget, resolveLaneModel, FOREGROUND_ONLY_RULE, STANDING_AUTHORIZATION, spawnLaneWorker, spawnEnvelopeRepairRequest, laneRunDir, readSpawnManifest, stopLaneProcesses, } from "../lib/lanes/spawn.js";
|
|
@@ -4524,6 +4527,7 @@ async function runShow(ctx, laneId) {
|
|
|
4524
4527
|
: storedLane;
|
|
4525
4528
|
const askDeliveryFailed = readJsonFile(askDeliveryFailedPath(hqRoot, laneId));
|
|
4526
4529
|
const keepAliveState = resolveLaneKeepAlive(hqRoot, storedLane);
|
|
4530
|
+
const keepAliveCompany = resolveLaneCompany(hqRoot, storedLane);
|
|
4527
4531
|
const doneStateVerdict = storedLane.state === "done" && storedLane.keep_alive === true
|
|
4528
4532
|
? doneKeepAliveVerdict(storedLane, { decision: storedLane.last_envelope?.decision, story_complete: storedLane.story_complete }, storedLane.keep_alive_standing === true && hasPendingKeepAliveWork(hqRoot, storedLane))
|
|
4529
4533
|
: null;
|
|
@@ -4533,6 +4537,10 @@ async function runShow(ctx, laneId) {
|
|
|
4533
4537
|
env: ctx.env,
|
|
4534
4538
|
now: ctx.now().getTime(),
|
|
4535
4539
|
});
|
|
4540
|
+
const krFreshness = await resolveKrFreshnessForShow(hqRoot, storedLane, {
|
|
4541
|
+
env: ctx.env,
|
|
4542
|
+
now: ctx.now().getTime(),
|
|
4543
|
+
});
|
|
4536
4544
|
printJson({
|
|
4537
4545
|
ok: true,
|
|
4538
4546
|
action: "show",
|
|
@@ -4562,6 +4570,8 @@ async function runShow(ctx, laneId) {
|
|
|
4562
4570
|
keep_alive_state: {
|
|
4563
4571
|
enabled: keepAliveState.enabled,
|
|
4564
4572
|
source: keepAliveState.source,
|
|
4573
|
+
company_source: keepAliveCompany.source,
|
|
4574
|
+
company_slug: keepAliveCompany.company?.slug ?? null,
|
|
4565
4575
|
standing: storedLane.keep_alive_standing === true,
|
|
4566
4576
|
done_state_verdict: doneStateVerdict,
|
|
4567
4577
|
opted_in_at: storedLane.keep_alive_opted_in_at ?? null,
|
|
@@ -4597,6 +4607,7 @@ async function runShow(ctx, laneId) {
|
|
|
4597
4607
|
blockerFreshnessFingerprint(blockerFreshness.stale),
|
|
4598
4608
|
}
|
|
4599
4609
|
: null,
|
|
4610
|
+
kr_freshness: krFreshness,
|
|
4600
4611
|
last_message_at: lane.last_message_at ?? null,
|
|
4601
4612
|
last_compaction: lane.last_compaction
|
|
4602
4613
|
? { ...lane.last_compaction, after: compactionAfterUsage(storedLane) }
|
|
@@ -6918,6 +6929,7 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
6918
6929
|
env: ctx.env,
|
|
6919
6930
|
}, wrap);
|
|
6920
6931
|
registerOutpostPrunerCommand(lanes);
|
|
6932
|
+
registerLaneKpisCommand(lanes, { hqRoot: ctx.hqRoot, now: ctx.now, wrap });
|
|
6921
6933
|
const noStoryOption = new Option("--no-story <reason>", "Create a lane without a story and record why");
|
|
6922
6934
|
noStoryOption.attributeName = () => "noStory";
|
|
6923
6935
|
lanes
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
import { type CompanyBriefResult } from "./company-brief.js";
|
|
11
11
|
import { type OntologyCompany } from "./company.js";
|
|
12
12
|
import { type MultiWriterStart } from "./multi-writer.js";
|
|
13
|
-
import { type EntityHint } from "./hints.js";
|
|
14
13
|
import { type SyncClientVersions } from "./sync-client.js";
|
|
15
14
|
export declare const ONTOLOGY_FLAG = "checkpoint.ontology";
|
|
16
15
|
/**
|
|
@@ -41,13 +40,6 @@ export declare const GROK_BACKEND_FLAG = "checkpoint.ontology.grok-backend";
|
|
|
41
40
|
* duplicate entities.
|
|
42
41
|
*/
|
|
43
42
|
export declare const MULTI_WRITER_FLAG = "checkpoint.ontology.multi-writer";
|
|
44
|
-
/**
|
|
45
|
-
* Each knowledge input lists the existing entities its text names
|
|
46
|
-
* (`known_entities`), and the model is told to use those names and to skip
|
|
47
|
-
* table rows, paths and slugs. CO-41: 11 of 93 creates in the CO-39 grok-4.6
|
|
48
|
-
* runs were model errors, 5 of them duplicates of an existing entity.
|
|
49
|
-
*/
|
|
50
|
-
export declare const ENTITY_HINTS_FLAG = "checkpoint.ontology.entity-hints";
|
|
51
43
|
/**
|
|
52
44
|
* A candidate that links to an existing entity adds no aliases to it; the plan
|
|
53
45
|
* carries `link_aliases: false` and apply honours it. CO-42: most aliases
|
|
@@ -138,8 +130,6 @@ export interface PlanInput {
|
|
|
138
130
|
missing_refs?: string[];
|
|
139
131
|
/** Run-directory-relative copy of `path` with annotator entity lists removed; same line numbers. */
|
|
140
132
|
read_path?: string;
|
|
141
|
-
/** Existing entities this input's text names; only when `checkpoint.ontology.entity-hints` is on. */
|
|
142
|
-
known_entities?: EntityHint[];
|
|
143
133
|
}
|
|
144
134
|
export interface OntologyPlan {
|
|
145
135
|
schema: typeof PLAN_SCHEMA;
|
|
@@ -208,7 +198,6 @@ export type PlanOutcome = {
|
|
|
208
198
|
companyBrief?: CompanyBriefResult;
|
|
209
199
|
};
|
|
210
200
|
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.";
|
|
211
|
-
export declare const ENTITY_HINTS_INSTRUCTIONS: string[];
|
|
212
201
|
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.";
|
|
213
202
|
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.";
|
|
214
203
|
export declare function ledgerPath(hqRoot: string, company: OntologyCompany): string;
|
|
@@ -13,7 +13,6 @@ import * as path from "node:path";
|
|
|
13
13
|
import { writeCompanyBrief } from "./company-brief.js";
|
|
14
14
|
import { resolveOntologyCompany, safeWriteFile, stateRoot } from "./company.js";
|
|
15
15
|
import { startMultiWriterRun } from "./multi-writer.js";
|
|
16
|
-
import { entityHints, wordWeights } from "./hints.js";
|
|
17
16
|
import { checkSyncClient, readSyncClientVersions } from "./sync-client.js";
|
|
18
17
|
import { buildEntityIndex, listKnowledgeFiles, listSignalFiles, readSignal } from "./tree.js";
|
|
19
18
|
export const ONTOLOGY_FLAG = "checkpoint.ontology";
|
|
@@ -45,13 +44,6 @@ export const GROK_BACKEND_FLAG = "checkpoint.ontology.grok-backend";
|
|
|
45
44
|
* duplicate entities.
|
|
46
45
|
*/
|
|
47
46
|
export const MULTI_WRITER_FLAG = "checkpoint.ontology.multi-writer";
|
|
48
|
-
/**
|
|
49
|
-
* Each knowledge input lists the existing entities its text names
|
|
50
|
-
* (`known_entities`), and the model is told to use those names and to skip
|
|
51
|
-
* table rows, paths and slugs. CO-41: 11 of 93 creates in the CO-39 grok-4.6
|
|
52
|
-
* runs were model errors, 5 of them duplicates of an existing entity.
|
|
53
|
-
*/
|
|
54
|
-
export const ENTITY_HINTS_FLAG = "checkpoint.ontology.entity-hints";
|
|
55
47
|
/**
|
|
56
48
|
* A candidate that links to an existing entity adds no aliases to it; the plan
|
|
57
49
|
* carries `link_aliases: false` and apply honours it. CO-42: most aliases
|
|
@@ -105,10 +97,6 @@ export const BUDGET = {
|
|
|
105
97
|
chunkTokens: 12_000,
|
|
106
98
|
};
|
|
107
99
|
export 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.";
|
|
108
|
-
export const ENTITY_HINTS_INSTRUCTIONS = [
|
|
109
|
-
"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.",
|
|
110
|
-
"Skip rows of a glossary or translation table, file and directory paths, and names built from tags or slugs.",
|
|
111
|
-
];
|
|
112
100
|
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.";
|
|
113
101
|
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.";
|
|
114
102
|
const CANDIDATE_INSTRUCTIONS = [
|
|
@@ -272,7 +260,6 @@ export async function planOntologyRun(options) {
|
|
|
272
260
|
const ignoreAnnotations = (await options.readFlag(IGNORE_ANNOTATIONS_FLAG, company)) && payload.backend === "grok";
|
|
273
261
|
recordBackendPreference(hqRoot, company, await options.readFlag(GROK_BACKEND_FLAG, company));
|
|
274
262
|
const multiWriterOn = await options.readFlag(MULTI_WRITER_FLAG, company);
|
|
275
|
-
const hintsOn = await options.readFlag(ENTITY_HINTS_FLAG, company);
|
|
276
263
|
const noLinkAliases = await options.readFlag(NO_LINK_ALIASES_FLAG, company);
|
|
277
264
|
const firstNamePeople = await options.readFlag(FIRST_NAME_PEOPLE_FLAG, company);
|
|
278
265
|
const skipAmbiguousConceptLinks = await options.readFlag(SKIP_AMBIGUOUS_CONCEPT_LINKS_FLAG, company);
|
|
@@ -289,15 +276,6 @@ export async function planOntologyRun(options) {
|
|
|
289
276
|
const pending = Object.entries(ledger.entries)
|
|
290
277
|
.filter(([, entry]) => entry.state === "pending" && entry.reason === "session-touched")
|
|
291
278
|
.sort(([aRel, a], [bRel, b]) => a.mtime_ms - b.mtime_ms || aRel.localeCompare(bRel));
|
|
292
|
-
// Built after merge-back, so merged entities are hinted too.
|
|
293
|
-
let hintIndex = null;
|
|
294
|
-
const hintsFor = (text) => {
|
|
295
|
-
if (!hintIndex) {
|
|
296
|
-
const index = buildEntityIndex(company.dir);
|
|
297
|
-
hintIndex = { index, weights: wordWeights(index) };
|
|
298
|
-
}
|
|
299
|
-
return entityHints(hintIndex.index, hintIndex.weights, text);
|
|
300
|
-
};
|
|
301
279
|
const inputs = [];
|
|
302
280
|
let tokens = 0;
|
|
303
281
|
let remaining = 0;
|
|
@@ -322,10 +300,6 @@ export async function planOntologyRun(options) {
|
|
|
322
300
|
const cost = estTokens(Buffer.byteLength(lines.slice(start - 1, end).join("\n"), "utf8"));
|
|
323
301
|
if (inputs.length >= BUDGET.maxInputs || tokens + cost > BUDGET.maxTokens)
|
|
324
302
|
break;
|
|
325
|
-
// The model reads the stripped copy when there is one; its line numbers match.
|
|
326
|
-
const knownEntities = hintsOn && kind === "knowledge"
|
|
327
|
-
? hintsFor((cleaned ?? text).split("\n").slice(start - 1, end).join("\n"))
|
|
328
|
-
: null;
|
|
329
303
|
inputs.push({
|
|
330
304
|
id: chunks.length > 1 ? `${rel}#${index}` : rel,
|
|
331
305
|
kind,
|
|
@@ -338,7 +312,6 @@ export async function planOntologyRun(options) {
|
|
|
338
312
|
chunk: chunks.length > 1 ? { index, count: chunks.length } : null,
|
|
339
313
|
...(kind === "signal" ? { missing_refs: missingRefs(company.dir, rel) } : {}),
|
|
340
314
|
...(readPath !== null ? { read_path: readPath } : {}),
|
|
341
|
-
...(knownEntities !== null ? { known_entities: knownEntities } : {}),
|
|
342
315
|
});
|
|
343
316
|
tokens += cost;
|
|
344
317
|
}
|
|
@@ -407,7 +380,6 @@ export async function planOntologyRun(options) {
|
|
|
407
380
|
...CANDIDATE_INSTRUCTIONS.slice(0, 3),
|
|
408
381
|
...(inputs.some((input) => input.read_path) ? [READ_PATH_INSTRUCTION] : []),
|
|
409
382
|
`${CANDIDATE_INSTRUCTIONS[3]} ${firstNamePeople ? FIRST_NAME_PEOPLE_INSTRUCTION : PERSON_NAME_INSTRUCTION}`,
|
|
410
|
-
...(inputs.some((input) => input.known_entities) ? ENTITY_HINTS_INSTRUCTIONS : []),
|
|
411
383
|
...CANDIDATE_INSTRUCTIONS.slice(4),
|
|
412
384
|
],
|
|
413
385
|
};
|
|
@@ -41,6 +41,8 @@ export declare const DEFAULT_SILENT_LOST_MS: number;
|
|
|
41
41
|
export declare const DEFAULT_SESSION_QUESTION_TIMEOUT_SECS: number;
|
|
42
42
|
/** Open manager blockers are re-verified every four hours by default. */
|
|
43
43
|
export declare const DEFAULT_BLOCKER_FRESHNESS_HOURS = 4;
|
|
44
|
+
/** Manager key results must be re-measured within six hours by default. */
|
|
45
|
+
export declare const DEFAULT_KR_FRESHNESS_HOURS = 6;
|
|
44
46
|
export declare const DEFAULT_TRACKER_CHECKS: TrackerChecksConfig;
|
|
45
47
|
export declare const DEFAULT_LIVENESS_WINDOWS: LivenessWindows;
|
|
46
48
|
export declare const DEFAULT_PROVIDER_MAX_RUNNING: Record<LaneProvider, number>;
|
package/dist/lib/lanes/config.js
CHANGED
|
@@ -45,6 +45,8 @@ export const DEFAULT_SILENT_LOST_MS = 12 * 60 * 60 * 1000;
|
|
|
45
45
|
export const DEFAULT_SESSION_QUESTION_TIMEOUT_SECS = 10 * 60;
|
|
46
46
|
/** Open manager blockers are re-verified every four hours by default. */
|
|
47
47
|
export const DEFAULT_BLOCKER_FRESHNESS_HOURS = 4;
|
|
48
|
+
/** Manager key results must be re-measured within six hours by default. */
|
|
49
|
+
export const DEFAULT_KR_FRESHNESS_HOURS = 6;
|
|
48
50
|
export const DEFAULT_TRACKER_CHECKS = {
|
|
49
51
|
owner_question_surface_ms: 10 * 60 * 1000,
|
|
50
52
|
open_question_age_ms: 2 * 60 * 60 * 1000,
|
|
@@ -425,6 +427,7 @@ export function documentedDefaultConfig(deps = defaultDeps()) {
|
|
|
425
427
|
tracker: { checks: { ...DEFAULT_TRACKER_CHECKS } },
|
|
426
428
|
session_question_timeout_secs: DEFAULT_SESSION_QUESTION_TIMEOUT_SECS,
|
|
427
429
|
blocker_freshness_hours: DEFAULT_BLOCKER_FRESHNESS_HOURS,
|
|
430
|
+
kr_freshness_hours: DEFAULT_KR_FRESHNESS_HOURS,
|
|
428
431
|
};
|
|
429
432
|
}
|
|
430
433
|
export function parseLanesConfig(raw, deps = defaultDeps()) {
|
|
@@ -468,6 +471,7 @@ export function parseLanesConfig(raw, deps = defaultDeps()) {
|
|
|
468
471
|
tracker: { checks: parseTrackerChecks(raw.tracker) },
|
|
469
472
|
session_question_timeout_secs: positiveInt(raw.session_question_timeout_secs, "session_question_timeout_secs", DEFAULT_SESSION_QUESTION_TIMEOUT_SECS),
|
|
470
473
|
blocker_freshness_hours: positiveNumber(raw.blocker_freshness_hours, "blocker_freshness_hours", DEFAULT_BLOCKER_FRESHNESS_HOURS),
|
|
474
|
+
kr_freshness_hours: positiveNumber(raw.kr_freshness_hours, "kr_freshness_hours", DEFAULT_KR_FRESHNESS_HOURS),
|
|
471
475
|
};
|
|
472
476
|
}
|
|
473
477
|
export function lanesConfigPath(hqRoot) {
|
|
@@ -40,7 +40,7 @@ export declare function retiredLaneRegistryPath(hqRoot: string): string;
|
|
|
40
40
|
export declare function loadRetiredLaneIds(hqRoot: string): ReadonlySet<string>;
|
|
41
41
|
/** IDs may be stored bare or with an owner-host suffix after an underscore. */
|
|
42
42
|
export declare function isRetiredLaneId(laneId: string, retiredLaneIds: ReadonlySet<string>): boolean;
|
|
43
|
-
export declare function keepAliveSupersededBy(lane: LaneRecord, lanes: readonly LaneRecord[], lineageAware?: boolean): LaneRecord | undefined;
|
|
44
|
-
export declare function keepAliveExclusion(lane: LaneRecord, lanes: readonly LaneRecord[], retiredLaneIds: ReadonlySet<string>, lineageAware?: boolean): "retired" | "superseded" | undefined;
|
|
43
|
+
export declare function keepAliveSupersededBy(lane: LaneRecord, lanes: readonly LaneRecord[], lineageAware?: boolean, companyForLane?: (lane: LaneRecord) => LaneRecord["company"]): LaneRecord | undefined;
|
|
44
|
+
export declare function keepAliveExclusion(lane: LaneRecord, lanes: readonly LaneRecord[], retiredLaneIds: ReadonlySet<string>, lineageAware?: boolean, companyForLane?: (lane: LaneRecord) => LaneRecord["company"]): "retired" | "superseded" | undefined;
|
|
45
45
|
export declare function leadLaneKeepAliveBackoffMs(attempt: number): number;
|
|
46
46
|
//# sourceMappingURL=keep-alive.d.ts.map
|
|
@@ -199,10 +199,12 @@ export function isRetiredLaneId(laneId, retiredLaneIds) {
|
|
|
199
199
|
}
|
|
200
200
|
return false;
|
|
201
201
|
}
|
|
202
|
-
export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED) {
|
|
202
|
+
export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED, companyForLane) {
|
|
203
203
|
const createdAt = Date.parse(lane.created_at);
|
|
204
204
|
if (!Number.isFinite(createdAt))
|
|
205
205
|
return undefined;
|
|
206
|
+
const companyOf = companyForLane ?? ((candidate) => candidate.company);
|
|
207
|
+
const laneCompany = companyOf(lane);
|
|
206
208
|
const lanesById = new Map(lanes.map((candidate) => [candidate.lane_id, candidate]));
|
|
207
209
|
const targetAncestorIds = new Set();
|
|
208
210
|
if (lineageAware) {
|
|
@@ -218,9 +220,10 @@ export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESS
|
|
|
218
220
|
return lanes.find((candidate) => {
|
|
219
221
|
if (candidate.lane_id === lane.lane_id || Date.parse(candidate.created_at) <= createdAt)
|
|
220
222
|
return false;
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
const candidateCompany = companyOf(candidate);
|
|
224
|
+
const sameCompany = laneCompany === null
|
|
225
|
+
? candidateCompany === null
|
|
226
|
+
: candidateCompany?.uid === laneCompany.uid;
|
|
224
227
|
if (!sameCompany)
|
|
225
228
|
return false;
|
|
226
229
|
if (lineageAware && targetAncestorIds.has(candidate.lane_id))
|
|
@@ -249,10 +252,10 @@ export function keepAliveSupersededBy(lane, lanes, lineageAware = LANE_SUPERSESS
|
|
|
249
252
|
return sameProfile || projectLead;
|
|
250
253
|
});
|
|
251
254
|
}
|
|
252
|
-
export function keepAliveExclusion(lane, lanes, retiredLaneIds, lineageAware = LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED) {
|
|
255
|
+
export function keepAliveExclusion(lane, lanes, retiredLaneIds, lineageAware = LANE_SUPERSESSION_LINEAGE_AWARE_DEFAULT_ENABLED, companyForLane) {
|
|
253
256
|
if (isRetiredLaneId(lane.lane_id, retiredLaneIds))
|
|
254
257
|
return "retired";
|
|
255
|
-
return keepAliveSupersededBy(lane, lanes, lineageAware) === undefined ? undefined : "superseded";
|
|
258
|
+
return keepAliveSupersededBy(lane, lanes, lineageAware, companyForLane) === undefined ? undefined : "superseded";
|
|
256
259
|
}
|
|
257
260
|
export function leadLaneKeepAliveBackoffMs(attempt) {
|
|
258
261
|
if (!Number.isSafeInteger(attempt) || attempt < 1) {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type ManagerStatusTarget } from "./manager-status-gate.js";
|
|
2
|
+
import { readLanesRegistryFlag } from "./registry-flag.js";
|
|
3
|
+
import type { LaneRecord } from "./types.js";
|
|
4
|
+
export declare const KR_FRESHNESS_FLAG = "lanes.kr-freshness";
|
|
5
|
+
export declare const KR_FRESHNESS_DEFAULT_HOURS = 6;
|
|
6
|
+
export declare const KR_FRESHNESS_LEDGER_REL: string;
|
|
7
|
+
export declare const KR_FRESHNESS_LEDGER_SCHEMA = "kr-freshness-ledger.v1";
|
|
8
|
+
export declare const KR_FRESHNESS_HISTORY_LIMIT = 50;
|
|
9
|
+
export type KrFreshnessVerdict = "moving" | "flat" | "stalled";
|
|
10
|
+
export interface KrFreshnessKpi {
|
|
11
|
+
name: string;
|
|
12
|
+
value: number | string;
|
|
13
|
+
entry_measured_at: string | null;
|
|
14
|
+
first_seen_at: string;
|
|
15
|
+
measured_at: string;
|
|
16
|
+
value_changed_at: string;
|
|
17
|
+
removed_at?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface KrFreshnessLedger {
|
|
20
|
+
schema_version: typeof KR_FRESHNESS_LEDGER_SCHEMA;
|
|
21
|
+
lane_id: string;
|
|
22
|
+
updated_at: string;
|
|
23
|
+
kpis: Record<string, KrFreshnessKpi>;
|
|
24
|
+
}
|
|
25
|
+
export interface KrFreshnessView {
|
|
26
|
+
name: string;
|
|
27
|
+
value: number | string;
|
|
28
|
+
verdict: KrFreshnessVerdict;
|
|
29
|
+
measured_at: string;
|
|
30
|
+
value_changed_at: string;
|
|
31
|
+
}
|
|
32
|
+
export interface KrFreshnessResolution {
|
|
33
|
+
flagEnabled: boolean;
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
target?: ManagerStatusTarget;
|
|
36
|
+
statusPath?: string;
|
|
37
|
+
windowHours: number;
|
|
38
|
+
kpis: KrFreshnessView[];
|
|
39
|
+
stalledKeys: string[];
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface KrFreshnessResolutionOptions {
|
|
43
|
+
env?: NodeJS.ProcessEnv;
|
|
44
|
+
now?: number;
|
|
45
|
+
readFlag?: typeof readLanesRegistryFlag;
|
|
46
|
+
onError?: (error: unknown) => void;
|
|
47
|
+
}
|
|
48
|
+
export interface KrFreshnessStatusKpi {
|
|
49
|
+
key: string;
|
|
50
|
+
fullName: string;
|
|
51
|
+
name: string;
|
|
52
|
+
value: number | string;
|
|
53
|
+
entryMeasuredAt: string | null;
|
|
54
|
+
}
|
|
55
|
+
export declare function readKrFreshnessStatus(statusPath: string): KrFreshnessStatusKpi[];
|
|
56
|
+
export declare function krFreshnessLedgerPath(root: string, laneId: string): string;
|
|
57
|
+
export declare function readKrFreshnessLedger(root: string, laneId: string): KrFreshnessLedger | null;
|
|
58
|
+
export declare function writeKrFreshnessLedger(root: string, ledger: KrFreshnessLedger): void;
|
|
59
|
+
export declare function updateKrFreshnessLedger(laneId: string, prior: KrFreshnessLedger | null, statusKpis: readonly KrFreshnessStatusKpi[], now: number): KrFreshnessLedger;
|
|
60
|
+
export declare function krFreshnessVerdict(kpi: Pick<KrFreshnessKpi, "measured_at" | "value_changed_at">, now: number, windowHours: number): KrFreshnessVerdict;
|
|
61
|
+
export declare function krFreshnessFingerprint(keys: readonly string[]): string;
|
|
62
|
+
/** Read the flag before manager mapping, status, configuration or ledger files. */
|
|
63
|
+
export declare function resolveKrFreshnessForLane(root: string, lane: LaneRecord, options?: KrFreshnessResolutionOptions): Promise<KrFreshnessResolution>;
|
|
64
|
+
/** Read a previously written ledger for `lanes show`; this never reads status. */
|
|
65
|
+
export declare function resolveKrFreshnessForShow(root: string, lane: LaneRecord, options?: KrFreshnessResolutionOptions): Promise<{
|
|
66
|
+
enabled: true;
|
|
67
|
+
kpis: KrFreshnessView[];
|
|
68
|
+
} | null>;
|
|
69
|
+
/** Operator report path: the ledger remains readable while runtime enforcement is off. */
|
|
70
|
+
export declare function readKrFreshnessReport(root: string, laneId: string, now: number): {
|
|
71
|
+
ledger_path: string;
|
|
72
|
+
available: boolean;
|
|
73
|
+
kr_freshness_hours: number;
|
|
74
|
+
kpis: KrFreshnessView[];
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=kr-freshness.d.ts.map
|