@mrciphersmith/keryx 0.3.112 → 0.3.113
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/README.md +17 -3
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/dist/cli.js +106311 -101534
- package/dist/core.js +5525 -4329
- package/package.json +3 -1
- package/src/gdgraph/affected-report.ts +14 -4
- package/src/gdgraph/build.ts +12 -9
- package/src/gdgraph/core-sources.ts +1 -0
- package/src/gdgraph/data-dir.ts +14 -0
- package/src/gdgraph/enrich.ts +5 -3
- package/src/gdgraph/query.ts +3 -2
- package/src/gdgraph/staleness.ts +8 -1
- package/src/gdgraph/wiki-layer.ts +9 -6
- package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +3 -3
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +3 -3
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/orchestrator-prompt.md +2 -2
- package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +4 -4
- package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +1 -1
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +3 -3
- package/src/gdskills/bundled/skills/quality/api-truth/SKILL.md +2 -2
- package/src/gdskills/bundled/skills/quality/deprecation-path/SKILL.md +3 -3
- package/src/gdskills/bundled/skills/quality/fresh-eyes/SKILL.md +2 -2
- package/src/gdskills/bundled/skills/quality/perf-check/SKILL.md +1 -1
- package/src/gdskills/bundled/skills/quality/root-cause/SKILL.md +2 -2
- package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +14 -15
- package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +14 -14
- package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +13 -16
- package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +14 -14
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +3 -3
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +19 -17
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +16 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +40 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-frontend.md +1 -1
- package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +13 -13
- package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +23 -25
- package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +13 -15
- package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +31 -57
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.113",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"test:client": "bun run test:client:terminal && bun run test:client:streaming && bun run test:client:cancel-resume && bun run test:client:runtime",
|
|
54
54
|
"check": "bun run lint && bun run typecheck && bun run typecheck:scripts && bun test",
|
|
55
55
|
"check:core": "bun run lint && bun run typecheck && bun run typecheck:scripts && bun run test:core",
|
|
56
|
+
"docs:build": "mkdocs build --strict",
|
|
56
57
|
"check:doc-links": "bun scripts/check-doc-links.ts",
|
|
57
58
|
"check:retired-spellings": "bun scripts/check-retired-cli-spellings.ts",
|
|
58
59
|
"baseline:review-precision": "bun scripts/review-precision-baseline.ts",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"src/gdskills/contracts",
|
|
68
69
|
"!src/**/*.test.ts",
|
|
69
70
|
"LICENSE",
|
|
71
|
+
"THIRD_PARTY_NOTICES.md",
|
|
70
72
|
"README.md",
|
|
71
73
|
"package.json"
|
|
72
74
|
],
|
|
@@ -25,6 +25,10 @@ import { explainAbsentGraphTarget, loadDeletionTrail } from "../forgetting/servi
|
|
|
25
25
|
export interface AffectedReportOptions {
|
|
26
26
|
depth?: number;
|
|
27
27
|
ranked?: boolean;
|
|
28
|
+
/** Read this gdgraph data directory (a review package's graph) instead of the project's own. */
|
|
29
|
+
dataDir?: string;
|
|
30
|
+
/** Freshness to report for a `dataDir` graph; the project graph's own staleness check says nothing about it. */
|
|
31
|
+
freshness?: StalenessCheck;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export interface AffectedReport {
|
|
@@ -58,7 +62,13 @@ export async function buildAffectedReport(
|
|
|
58
62
|
const depth = opts.depth !== undefined && Number.isFinite(opts.depth) ? opts.depth : config.affected.defaultDepth;
|
|
59
63
|
const ranked = opts.ranked ?? true;
|
|
60
64
|
|
|
61
|
-
const graph = await loadGraph(root);
|
|
65
|
+
const graph = await loadGraph(root, opts.dataDir);
|
|
66
|
+
const freshnessOf = (): Promise<StalenessCheck> =>
|
|
67
|
+
opts.dataDir === undefined
|
|
68
|
+
? checkGraphStaleness(root)
|
|
69
|
+
: Promise.resolve(
|
|
70
|
+
opts.freshness ?? { status: "unknown", reasons: ["package graph: freshness is recorded in layers.json"] },
|
|
71
|
+
);
|
|
62
72
|
|
|
63
73
|
// Symbol-aware: if the target isn't a known file but names a symbol,
|
|
64
74
|
// resolve it to its owning file — mirrors `runAffected`'s own resolution.
|
|
@@ -83,7 +93,7 @@ export async function buildAffectedReport(
|
|
|
83
93
|
"the graph index holds no file nodes — it was never built here, or its storage is unreadable. " +
|
|
84
94
|
"No claim is being made about whether this target exists.",
|
|
85
95
|
);
|
|
86
|
-
const freshness = await
|
|
96
|
+
const freshness = await freshnessOf();
|
|
87
97
|
return {
|
|
88
98
|
exitCode: 1,
|
|
89
99
|
resolutionNote,
|
|
@@ -108,7 +118,7 @@ export async function buildAffectedReport(
|
|
|
108
118
|
`gdgraph: "${target}" is not a node in the built graph (never indexed, or the ` +
|
|
109
119
|
`path/symbol does not exist) — this is not the same as an indexed target with ` +
|
|
110
120
|
`zero edges. Run \`keryx gdgraph build\` if the file is new, or double-check the path.`;
|
|
111
|
-
const freshness = await
|
|
121
|
+
const freshness = await freshnessOf();
|
|
112
122
|
return {
|
|
113
123
|
exitCode: 1,
|
|
114
124
|
resolutionNote,
|
|
@@ -132,7 +142,7 @@ export async function buildAffectedReport(
|
|
|
132
142
|
};
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
const freshness: StalenessCheck = await
|
|
145
|
+
const freshness: StalenessCheck = await freshnessOf();
|
|
136
146
|
return {
|
|
137
147
|
exitCode: 0,
|
|
138
148
|
resolutionNote,
|
package/src/gdgraph/build.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { gdgraphArtifactsDir, gdgraphStorageDir } from "./data-dir";
|
|
4
5
|
import type { GraphData, GraphEdge, GraphNode, ImportKind, TranspilerImportKind } from "./types";
|
|
5
6
|
import { TYPE_ONLY_IMPORT_KIND, UNKNOWN_IMPORT_KIND } from "./types";
|
|
6
7
|
|
|
@@ -100,7 +101,8 @@ type ResolverSet = {
|
|
|
100
101
|
python: ImportResolver;
|
|
101
102
|
};
|
|
102
103
|
|
|
103
|
-
export async function buildGraph(projectRoot: string): Promise<BuildResult> {
|
|
104
|
+
export async function buildGraph(projectRoot: string, options: { dataDir?: string } = {}): Promise<BuildResult> {
|
|
105
|
+
const { dataDir } = options;
|
|
104
106
|
const collection = await collectSourceFiles(projectRoot);
|
|
105
107
|
const files = collection.files;
|
|
106
108
|
const fileSet = new Set(files);
|
|
@@ -157,8 +159,8 @@ export async function buildGraph(projectRoot: string): Promise<BuildResult> {
|
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
const graph = { nodes: [...nodes, ...assetNodes.values()].sort((a, b) => a.path.localeCompare(b.path)), edges };
|
|
160
|
-
await writeGraph(projectRoot, graph);
|
|
161
|
-
const summaryPath = await writeSummary(projectRoot, graph, collection);
|
|
162
|
+
await writeGraph(projectRoot, graph, dataDir);
|
|
163
|
+
const summaryPath = await writeSummary(projectRoot, graph, collection, dataDir);
|
|
162
164
|
|
|
163
165
|
// B1: after the UNCHANGED file-level build, optionally enrich with the
|
|
164
166
|
// tree-sitter symbol layer behind the Block 0 capability seam. Loaded
|
|
@@ -168,7 +170,7 @@ export async function buildGraph(projectRoot: string): Promise<BuildResult> {
|
|
|
168
170
|
// artifacts stay byte-identical (the golden rule, B-1/C0-7/F-3).
|
|
169
171
|
try {
|
|
170
172
|
const { enrichBuildWithSymbols } = await import("./enrich");
|
|
171
|
-
await enrichBuildWithSymbols(projectRoot, fileRecords);
|
|
173
|
+
await enrichBuildWithSymbols(projectRoot, fileRecords, undefined, dataDir);
|
|
172
174
|
} catch {
|
|
173
175
|
// Enrichment module or seam unavailable ⇒ file-level graph only.
|
|
174
176
|
}
|
|
@@ -180,7 +182,7 @@ export async function buildGraph(projectRoot: string): Promise<BuildResult> {
|
|
|
180
182
|
// `edges.jsonl` written above are never revisited (AC13).
|
|
181
183
|
try {
|
|
182
184
|
const { enrichBuildWithWikiLayer } = await import("./wiki-layer");
|
|
183
|
-
await enrichBuildWithWikiLayer({ projectRoot, graph, fileRecords });
|
|
185
|
+
await enrichBuildWithWikiLayer({ projectRoot, graph, fileRecords, ...(dataDir === undefined ? {} : { dataDir }) });
|
|
184
186
|
} catch {
|
|
185
187
|
// Wiki absent, unreadable, or the layer module unavailable ⇒ no layer.
|
|
186
188
|
}
|
|
@@ -887,9 +889,9 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
887
889
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
888
890
|
}
|
|
889
891
|
|
|
890
|
-
async function writeGraph(projectRoot: string, graph: GraphData): Promise<void> {
|
|
891
|
-
const storageDir =
|
|
892
|
-
const artifactsDir =
|
|
892
|
+
async function writeGraph(projectRoot: string, graph: GraphData, dataDir?: string): Promise<void> {
|
|
893
|
+
const storageDir = gdgraphStorageDir(projectRoot, dataDir);
|
|
894
|
+
const artifactsDir = gdgraphArtifactsDir(projectRoot, dataDir);
|
|
893
895
|
await mkdir(storageDir, { recursive: true });
|
|
894
896
|
await mkdir(artifactsDir, { recursive: true });
|
|
895
897
|
|
|
@@ -914,8 +916,9 @@ async function writeSummary(
|
|
|
914
916
|
projectRoot: string,
|
|
915
917
|
graph: GraphData,
|
|
916
918
|
collection: SourceCollection,
|
|
919
|
+
dataDir?: string,
|
|
917
920
|
): Promise<string> {
|
|
918
|
-
const artifactsDir =
|
|
921
|
+
const artifactsDir = gdgraphArtifactsDir(projectRoot, dataDir);
|
|
919
922
|
await mkdir(artifactsDir, { recursive: true });
|
|
920
923
|
|
|
921
924
|
const unresolved = graph.edges.filter((edge) => edge.kind === "unresolved");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
/** The gdgraph data directory (holds `storage/` and `artifacts/`): the project's own unless a caller names another. */
|
|
4
|
+
export function gdgraphDataDir(projectRoot: string, dataDir?: string): string {
|
|
5
|
+
return dataDir ?? path.join(projectRoot, ".metaproject", "data", "gdgraph");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function gdgraphStorageDir(projectRoot: string, dataDir?: string): string {
|
|
9
|
+
return path.join(gdgraphDataDir(projectRoot, dataDir), "storage");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function gdgraphArtifactsDir(projectRoot: string, dataDir?: string): string {
|
|
13
|
+
return path.join(gdgraphDataDir(projectRoot, dataDir), "artifacts");
|
|
14
|
+
}
|
package/src/gdgraph/enrich.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type CapabilitySpec,
|
|
18
18
|
} from "../capability/seam";
|
|
19
19
|
import { loadGdgraphConfig } from "./config";
|
|
20
|
+
import { gdgraphStorageDir } from "./data-dir";
|
|
20
21
|
import {
|
|
21
22
|
createTreesitterSpec,
|
|
22
23
|
resolveTreesitterCapability,
|
|
@@ -45,6 +46,7 @@ export async function enrichBuildWithSymbols(
|
|
|
45
46
|
// `resolveTreesitterCapability`; tests pass an explicit `CapabilityResolver`
|
|
46
47
|
// (e.g. a mock adapter, or the raw seam) to bypass it.
|
|
47
48
|
resolve?: CapabilityResolver,
|
|
49
|
+
dataDir?: string,
|
|
48
50
|
): Promise<EnrichResult> {
|
|
49
51
|
const config = await loadGdgraphConfig(cwd);
|
|
50
52
|
const treesitterConfig = {
|
|
@@ -76,12 +78,12 @@ export async function enrichBuildWithSymbols(
|
|
|
76
78
|
() => ({ symbols: [], calls: [] }),
|
|
77
79
|
);
|
|
78
80
|
|
|
79
|
-
await writeSymbolLayer(cwd, layer);
|
|
81
|
+
await writeSymbolLayer(cwd, layer, dataDir);
|
|
80
82
|
return { enriched: true, symbols: layer.symbols.length, calls: layer.calls.length };
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
async function writeSymbolLayer(cwd: string, layer: SymbolLayer): Promise<void> {
|
|
84
|
-
const storageDir =
|
|
85
|
+
async function writeSymbolLayer(cwd: string, layer: SymbolLayer, dataDir?: string): Promise<void> {
|
|
86
|
+
const storageDir = gdgraphStorageDir(cwd, dataDir);
|
|
85
87
|
await mkdir(storageDir, { recursive: true });
|
|
86
88
|
await writeFile(
|
|
87
89
|
path.join(storageDir, "symbols.jsonl"),
|
package/src/gdgraph/query.ts
CHANGED
|
@@ -10,10 +10,11 @@ import type {
|
|
|
10
10
|
WikiPageNode,
|
|
11
11
|
} from "./types";
|
|
12
12
|
import { TYPE_ONLY_IMPORT_KIND } from "./types";
|
|
13
|
+
import { gdgraphStorageDir } from "./data-dir";
|
|
13
14
|
import { resolveGraphTarget } from "./target";
|
|
14
15
|
|
|
15
|
-
export async function loadGraph(projectRoot: string): Promise<GraphData> {
|
|
16
|
-
const storageDir =
|
|
16
|
+
export async function loadGraph(projectRoot: string, dataDir?: string): Promise<GraphData> {
|
|
17
|
+
const storageDir = gdgraphStorageDir(projectRoot, dataDir);
|
|
17
18
|
const nodes = await readJsonl<GraphNode>(path.join(storageDir, "nodes.jsonl"));
|
|
18
19
|
const edges = await readJsonl<GraphEdge>(path.join(storageDir, "edges.jsonl"));
|
|
19
20
|
// B1 symbol layer: loaded ONLY if present. Missing files ⇒ empty/omitted layer
|
package/src/gdgraph/staleness.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { revisionOperand } from "../lib/git-revision";
|
|
4
5
|
import { gitCmd, gitHead, readProvenance } from "../sync/provenance";
|
|
5
6
|
|
|
6
7
|
// W7 AC4 follow-up (flow 304 T8) — a real, previously-latent defect found
|
|
@@ -237,7 +238,13 @@ async function committedChangedFiles(
|
|
|
237
238
|
// "HEAD moved" reason. `--name-only -z` lists only the destination path per
|
|
238
239
|
// entry even for a rename (unlike `git status -z`, which pairs it with an
|
|
239
240
|
// orig-path field), so this stays a plain NUL-split with no pairing logic.
|
|
240
|
-
|
|
241
|
+
let diff: string | null;
|
|
242
|
+
try {
|
|
243
|
+
diff = await gitCmd(cwd, ["diff", "--name-only", "-z", ...revisionOperand(fromCommit), toCommit]);
|
|
244
|
+
} catch {
|
|
245
|
+
// A provenance commit that reads as an option is refused by revisionOperand; this check never throws.
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
241
248
|
if (diff === null) {
|
|
242
249
|
return [];
|
|
243
250
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import { mkdir, stat, writeFile } from "node:fs/promises";
|
|
17
17
|
import path from "node:path";
|
|
18
|
+
import { gdgraphStorageDir } from "./data-dir";
|
|
18
19
|
import { collectPages } from "../wiki/collect";
|
|
19
20
|
import { computeModuleKeyFiles } from "../wiki/collect";
|
|
20
21
|
import { resolveDescribeSet } from "../wiki/describes";
|
|
@@ -25,8 +26,8 @@ export const WIKI_PAGES_FILE = "wiki-pages.jsonl";
|
|
|
25
26
|
export const DESCRIBES_FILE = "describes.jsonl";
|
|
26
27
|
export const BUILD_MANIFEST_FILE = "build-manifest.json";
|
|
27
28
|
|
|
28
|
-
function storageDir(projectRoot: string): string {
|
|
29
|
-
return
|
|
29
|
+
function storageDir(projectRoot: string, dataDir?: string): string {
|
|
30
|
+
return gdgraphStorageDir(projectRoot, dataDir);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -181,8 +182,10 @@ export async function enrichBuildWithWikiLayer(input: {
|
|
|
181
182
|
/** Injected in tests; defaults to the real `validModuleNames`. */
|
|
182
183
|
validModules?: Set<string> | undefined;
|
|
183
184
|
loadValidModules?: (projectRoot: string) => Promise<Set<string> | undefined>;
|
|
185
|
+
/** A gdgraph data directory other than the project's own (a review package's graph). */
|
|
186
|
+
dataDir?: string;
|
|
184
187
|
}): Promise<WikiLayer> {
|
|
185
|
-
const dir = storageDir(input.projectRoot);
|
|
188
|
+
const dir = storageDir(input.projectRoot, input.dataDir);
|
|
186
189
|
await mkdir(dir, { recursive: true });
|
|
187
190
|
|
|
188
191
|
const mtimes = new Map<string, number>();
|
|
@@ -205,7 +208,7 @@ export async function enrichBuildWithWikiLayer(input: {
|
|
|
205
208
|
const validModules =
|
|
206
209
|
input.validModules !== undefined
|
|
207
210
|
? input.validModules
|
|
208
|
-
: await (input.loadValidModules ?? defaultLoadValidModules)(input.projectRoot);
|
|
211
|
+
: await (input.loadValidModules ?? ((root) => defaultLoadValidModules(root, input.dataDir)))(input.projectRoot);
|
|
209
212
|
|
|
210
213
|
const wikiPages = await collectPages(input.projectRoot);
|
|
211
214
|
const contents = new Map<string, string>();
|
|
@@ -236,9 +239,9 @@ export async function enrichBuildWithWikiLayer(input: {
|
|
|
236
239
|
return layer;
|
|
237
240
|
}
|
|
238
241
|
|
|
239
|
-
async function defaultLoadValidModules(projectRoot: string): Promise<Set<string> | undefined> {
|
|
242
|
+
async function defaultLoadValidModules(projectRoot: string, dataDir?: string): Promise<Set<string> | undefined> {
|
|
240
243
|
// Dynamic so `gdgraph` keeps no static dependency on `wiki/service`, which
|
|
241
244
|
// reads the graph itself — the same cycle-avoidance the symbol layer uses.
|
|
242
245
|
const { validModuleNames } = await import("../wiki/service");
|
|
243
|
-
return validModuleNames(projectRoot);
|
|
246
|
+
return validModuleNames(projectRoot, dataDir);
|
|
244
247
|
}
|
|
@@ -23,7 +23,7 @@ license: "MIT"
|
|
|
23
23
|
|
|
24
24
|
## Preflight
|
|
25
25
|
|
|
26
|
-
Run in the main session: this skill dispatches workers. Without
|
|
26
|
+
Run in the main session: this skill dispatches workers. Without a subagent-spawn tool (`Agent`, `spawn_subagent` or the host's equivalent), or with the depth budget spent (Claude Code nests at most 3 deep), the whole output is this line, with no tool calls and no work of your own: `STATUS: BLOCKED nested_dispatch_unavailable — run this skill in the main session`
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
29
29
|
|
|
@@ -560,7 +560,7 @@ the bound plus an escalation — never an unbounded loop.
|
|
|
560
560
|
**0.820 -> 0.673** across two forced revisions while cumulative ever-correct
|
|
561
561
|
is **0.847** ([arXiv:2607.24604](https://arxiv.org/abs/2607.24604)) — the
|
|
562
562
|
agent finds the fix and then destroys it, throwing away ~15 points by not
|
|
563
|
-
stopping.
|
|
563
|
+
stopping. Other agent tools hardcode the same bound (`max_reflections = 3`).
|
|
564
564
|
Rounds four through six of a self-fix loop were not buying convergence; they
|
|
565
565
|
were buying regressions. Review rounds are the exception, as stated above.
|
|
566
566
|
|
|
@@ -690,5 +690,5 @@ Stop and re-read this skill if you are thinking:
|
|
|
690
690
|
| "Tests pass and the review is clean, so I'll open the PR and complete the flow." | Phase 4 stops and asks the user how the flow should end; not every flow wants a PR. And completion requires a confirmed merge into the base branch captured at creation — not a green local run. |
|
|
691
691
|
| "The worker returned BLOCKED twice — faster if I implement this task myself." | The implementer never self-accepts and the orchestrator never implements. Block the flow, escalate one concise question, then unblock and re-dispatch. Doing the work here erases the boundary the whole flow model rests on. |
|
|
692
692
|
| "Verification is described in the plan, so it will happen." | A verification step in the plan is a task, not a sentence. If it is not a task with a status, nothing records whether it ran, and the flow reaches `implemented` with an unrun gate. |
|
|
693
|
-
| "The review fan-out is cheap, so the budget check can wait." | `keryx review budget --spent … --outstanding …` gates the fan-out, and `review-orchestrator`
|
|
693
|
+
| "The review fan-out is cheap, so the budget check can wait." | `keryx review budget --spent … --outstanding …` gates the fan-out, and `review-orchestrator` runs inline in this same main session, where keryx cannot see the in-flight subagents; declare them with `--outstanding`. Skipping the check means the cap bounds nothing. |
|
|
694
694
|
| "I'll set the verification kind later." | An `unclassified` criterion cannot become data afterwards without a recorded rewrite: `keryx flow ac update <id> --criterion ACn --text "…" --reason "<why>"`. Put the `[verify: …]` marker on every criterion before `flow freeze`. |
|
|
@@ -26,7 +26,7 @@ license: "MIT"
|
|
|
26
26
|
|
|
27
27
|
## Preflight
|
|
28
28
|
|
|
29
|
-
Run in the main session: this skill dispatches sub-agents. Without
|
|
29
|
+
Run in the main session: this skill dispatches sub-agents. Without a subagent-spawn tool (`Agent`, `spawn_subagent` or the host's equivalent), or with the depth budget spent (Claude Code nests at most 3 deep), the whole output is this line, with no tool calls and no work of your own: `STATUS: BLOCKED nested_dispatch_unavailable — run this skill in the main session`
|
|
30
30
|
|
|
31
31
|
## Purpose
|
|
32
32
|
|
|
@@ -1262,8 +1262,8 @@ Three is the self-fix bound `task-implementer` and this skill share
|
|
|
1262
1262
|
most achievable gains"* ([arXiv:2607.05197](https://arxiv.org/abs/2607.05197));
|
|
1263
1263
|
correctness falls **0.820 -> 0.673** across two forced revisions while
|
|
1264
1264
|
cumulative ever-correct is **0.847**
|
|
1265
|
-
([arXiv:2607.24604](https://arxiv.org/abs/2607.24604)).
|
|
1266
|
-
|
|
1265
|
+
([arXiv:2607.24604](https://arxiv.org/abs/2607.24604)). Other agent tools
|
|
1266
|
+
hardcode the same bound (`max_reflections = 3`).
|
|
1267
1267
|
|
|
1268
1268
|
The bound is a ceiling, not a target. Repetition ends the loop earlier and
|
|
1269
1269
|
**regardless of remaining iterations** — a counter cannot tell "converging
|
|
@@ -22,7 +22,7 @@ Phase 2: Execute plan, bracketing every step with keryx job step:
|
|
|
22
22
|
├─ git worktree add → feature branch (NEVER git checkout -b)
|
|
23
23
|
├─ FOR EACH wave → [tests-creator × tasks] then [task-implementer × tasks]
|
|
24
24
|
├─ [code-verifier sub-agent] → quality gate
|
|
25
|
-
├─ keryx review start → [review-orchestrator
|
|
25
|
+
├─ keryx review start → [review-orchestrator, inline] → keryx review ingest
|
|
26
26
|
├─ IF blocker/major → [task-implementer (fix)] → next managed round (max 3)
|
|
27
27
|
├─ keryx review complete --finding … --disposition … --evidence …
|
|
28
28
|
└─ keryx job document → each step's artifact recorded in the package
|
|
@@ -162,7 +162,7 @@ keryx review scope --ref "$BASE_SHA" --json > scope.json
|
|
|
162
162
|
keryx review blast-radius --ref "$BASE_SHA" --json > blast-radius.json # KEEP BOTH
|
|
163
163
|
keryx review stack --json # which reviewers apply
|
|
164
164
|
keryx review tier --scope <scope> --diff-lines <n> --json # model per dispatch
|
|
165
|
-
#
|
|
165
|
+
# run review-orchestrator inline (skills/gdskills/review/review-orchestrator/SKILL.md);
|
|
166
166
|
# it runs review-verifier in Wave C and emits the ```json keryx:findings``` block
|
|
167
167
|
keryx review ingest --report <report.md> --ref <feature-branch> --head <sha> \
|
|
168
168
|
--scope scope.json --blast-radius blast-radius.json \
|
|
@@ -368,8 +368,8 @@ account for most achievable gains"*
|
|
|
368
368
|
([arXiv:2607.05197](https://arxiv.org/abs/2607.05197)); correctness falls
|
|
369
369
|
**0.820 -> 0.673** across two forced revisions while cumulative ever-correct is
|
|
370
370
|
**0.847** ([arXiv:2607.24604](https://arxiv.org/abs/2607.24604)) — the agent
|
|
371
|
-
finds the fix and then destroys it.
|
|
372
|
-
|
|
371
|
+
finds the fix and then destroys it. Other agent tools hardcode the same bound
|
|
372
|
+
(`max_reflections = 3`).
|
|
373
373
|
|
|
374
374
|
**Stop earlier on repetition, whatever the count says.** If an attempt produces
|
|
375
375
|
the same failure output as the previous attempt — the same failing test with the
|
|
@@ -435,8 +435,8 @@ Write full JSON to `<JOBS_ROOT>/<JOB_NAME>/results/<task_id>.json`:
|
|
|
435
435
|
Set `skill_drift` from Phase 2.0b: if the project-skill you used was not `fresh`, or the code you wrote diverged from what a skill documents, name the skill and the divergence. The orchestrator uses this to decide whether to trigger `skills learn` (do NOT run `learn` yourself — it is a mutating step the orchestrator dispatches; see `rules/core/skill-lifecycle.mdc`).
|
|
436
436
|
|
|
437
437
|
Three of those fields have a bar, and a field that collects noise trains the
|
|
438
|
-
reader to skim all three. Omit one rather than pad it. The trio is adapted (MIT
|
|
439
|
-
|
|
438
|
+
reader to skim all three. Omit one rather than pad it. The trio is adapted (MIT;
|
|
439
|
+
see THIRD_PARTY_NOTICES.md) as contract fields rather than a free-text template; the bars below are ours.
|
|
440
440
|
|
|
441
441
|
- `assumptions` — what you assumed where the task was silent AND acted on. If
|
|
442
442
|
the assumption being wrong would not change a line you wrote, it is a hedge,
|
|
@@ -20,7 +20,7 @@ metadata:
|
|
|
20
20
|
version: 1.0.0
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
**Preflight:** run in the main session. Without
|
|
23
|
+
**Preflight:** run in the main session. Without a subagent-spawn tool (`Agent`, `spawn_subagent` or the host's equivalent) or depth budget, output only `STATUS: BLOCKED nested_dispatch_unavailable — run this skill in the main session`, with no tool calls.
|
|
24
24
|
|
|
25
25
|
# autodoc-orchestrator
|
|
26
26
|
|
|
@@ -93,8 +93,8 @@ Before the first question, check whether a host can show it: the `ask_user` tool
|
|
|
93
93
|
|
|
94
94
|
- **Host present:** ask every question through `ask_user`, one per call, with the A/B/C/D options as its options.
|
|
95
95
|
- **No host:** ask NO question, not even in plain text; nobody is there to answer it. Return `status: "NEEDS_CONTEXT"` with the `assumptions` you would have asked about (question, assumption, `confidence: "assumption"`), `ready_to_proceed: false`. The caller decides.
|
|
96
|
-
- A cancelled or empty `ask_user` answer is not an answer: record it as an assumption and stop asking.
|
|
97
|
-
- Each `ask_user` question is recorded in the recommendation journal by the tool itself (source, arm, recommendation, answer); you do not record it. `src/decisions/interviewer-path.test.ts` pins this path through the agent's real tool roster.
|
|
96
|
+
- A "No one was asked", cancelled or empty `ask_user` answer is not an answer: record it as an assumption and stop asking.
|
|
97
|
+
- Each `ask_user` question a person answers is recorded in the recommendation journal by the tool itself (source, arm, recommendation, answer); you do not record it. A question the model answered itself under `/mode auto` never reached a person and is not journaled: treat its answer as an assumption, not a decision. `src/decisions/interviewer-path.test.ts` pins this path through the agent's real tool roster.
|
|
98
98
|
|
|
99
99
|
## Question Bank by Goal Type
|
|
100
100
|
|
|
@@ -110,7 +110,7 @@ Stop and re-read this skill if you are thinking:
|
|
|
110
110
|
|---|---|
|
|
111
111
|
| "These three questions are related, so I'll ask them in one message to save time." | One question at a time is the rule, and it is not politeness. A batch gets one answer to the easiest item and silence on the rest, which you then record as if it had been answered. |
|
|
112
112
|
| "The answer was vague, but I understood the gist, so `ready_to_proceed: true`." | A gist is an assumption. Either ask the follow-up, or record the item in `blockers` with `confidence: "assumption"` and leave `ready_to_proceed` false. Proceeding on a gist is exactly the wasted work this gate exists to prevent. |
|
|
113
|
-
| "They said 'sure, that sounds about right', so that is a yes and `ready_to_proceed: true`." | A hedge is not a refusal and it is not approval. This is not the vague-answer case above — you understood the answer perfectly, and it committed the user to nothing. Name the hedge back ("that is a 'probably' — is it a yes?") and ask the question that forces one. If no commitment comes, the item is recorded as `confidence: "assumption"`, never as confirmation. (That a hedged agreement is not approval is adapted (MIT
|
|
113
|
+
| "They said 'sure, that sounds about right', so that is a yes and `ready_to_proceed: true`." | A hedge is not a refusal and it is not approval. This is not the vague-answer case above — you understood the answer perfectly, and it committed the user to nothing. Name the hedge back ("that is a 'probably' — is it a yes?") and ask the question that forces one. If no commitment comes, the item is recorded as `confidence: "assumption"`, never as confirmation. (That a hedged agreement is not approval is adapted (MIT; see THIRD_PARTY_NOTICES.md); naming the hedge back and the confidence enum are ours.) |
|
|
114
114
|
| "I inferred the answer from the codebase, so I can mark it `certain`." | `certain` means the user said it. An inference is `assumption`, even a good one — the confidence field is the only signal downstream skills have about which parts of `derived_context` are load-bearing guesses. |
|
|
115
115
|
| "I've hit the 8-question limit and still don't know, so I'll pick the likely answer." | The limit is a stop rule, not a licence to invent. Remaining unknowns go into `blockers`, `ready_to_proceed` goes false, and the caller decides. |
|
|
116
116
|
| "Context-collector already ran, so anything still missing must not matter." | Collected context answers what the codebase knows, not what the user intends. Scope, priority and what must NOT change are never in the codebase, and those are the answers that change the approach. |
|
|
@@ -221,6 +221,6 @@ Do not report the work as done until all of these hold:
|
|
|
221
221
|
upgrade decision for the dependency's owner, and no version was bumped inside
|
|
222
222
|
this change to obtain it.
|
|
223
223
|
|
|
224
|
-
Credit:
|
|
225
|
-
|
|
224
|
+
Credit: an MIT-licensed skills library (see THIRD_PARTY_NOTICES.md) is where
|
|
225
|
+
the pairing comes from — check the dependency before calling it,
|
|
226
226
|
and mark what went out unchecked. The ranks and the version rule are ours.
|
|
@@ -263,6 +263,6 @@ Do not report the work as done until all of these hold:
|
|
|
263
263
|
— a guess dressed as a schedule is neither — and the caller has the
|
|
264
264
|
before-and-after to migrate unaided, under behaviour unchanged under them.
|
|
265
265
|
|
|
266
|
-
Credit:
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
Credit: an MIT-licensed skills library (see THIRD_PARTY_NOTICES.md) is why this
|
|
267
|
+
set carries a deprecation skill at all; the five stages and the notice rule
|
|
268
|
+
were measured from keryx's own CLI, not taken from there.
|
|
@@ -185,6 +185,6 @@ A cycle is complete only when all of these hold:
|
|
|
185
185
|
- If the cycle found nothing, it says so plainly, with what was checked and what
|
|
186
186
|
was left unreached. `STATUS: NO FINDINGS` is a pass, not an incomplete run.
|
|
187
187
|
|
|
188
|
-
Credit:
|
|
189
|
-
|
|
188
|
+
Credit: an MIT-licensed skills library (see THIRD_PARTY_NOTICES.md) is where
|
|
189
|
+
the in-flight doubt pass comes from: a reader gets the artifact
|
|
190
190
|
and the contract, never the author's reasoning. The bar and the bound are ours.
|
|
@@ -77,7 +77,7 @@ Flag heavy dependencies:
|
|
|
77
77
|
## Rules
|
|
78
78
|
|
|
79
79
|
- Don't make changes — only analyze and report
|
|
80
|
-
- An optimisation that measures neutral is reported with revert as its recommended fix, not as harmless. The burden is on keeping it, never on dropping it: it leaves the code more complicated than it found it, and it survives review precisely because nothing is wrong with it. This rule and the ledger two bullets down are adapted (MIT
|
|
80
|
+
- An optimisation that measures neutral is reported with revert as its recommended fix, not as harmless. The burden is on keeping it, never on dropping it: it leaves the code more complicated than it found it, and it survives review precisely because nothing is wrong with it. This rule and the ledger two bullets down are adapted (MIT; see THIRD_PARTY_NOTICES.md); the noise definition and the groundwork exception are ours
|
|
81
81
|
- Neutral is a delta that does not clear the noise. Take the before reading three times on one named workload and keep the spread; any after-delta inside that spread is neutral. Indistinguishable from zero is the same verdict as zero, not a smaller win — say which it was, and how many runs said so
|
|
82
82
|
- Record the attempt in the flow journal (`.metaproject/flows/<flow>/journal.md`), in the same change as the revert: what was tried, the before and after with the command and the workload that produced them, and why it did not help *here*. "Tried caching, didn't help" is worse than no entry — it forecloses the idea for the next agent and leaves them nothing to overturn it with
|
|
83
83
|
- Groundwork is the only exception: a neutral change survives when the change it is a prerequisite for is in the same branch and the two measure a win together. A payoff promised for later is not a measurement — revert, and record what the pair would have to show
|
|
@@ -199,6 +199,6 @@ Report the defect fixed only when all of these hold:
|
|
|
199
199
|
the evidence and its class, the surviving hypotheses with their killing
|
|
200
200
|
observations, and the instrumentation that would settle it.
|
|
201
201
|
|
|
202
|
-
Credit:
|
|
203
|
-
|
|
202
|
+
Credit: an MIT-licensed skills library (see THIRD_PARTY_NOTICES.md) is why
|
|
203
|
+
this set carries a debugging skill at all; the step order, the
|
|
204
204
|
evidence classes and the non-reproduction protocol were written here, not taken.
|
|
@@ -348,21 +348,7 @@ STATUS: DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED
|
|
|
348
348
|
|
|
349
349
|
## Job Context Awareness
|
|
350
350
|
|
|
351
|
-
When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY
|
|
352
|
-
|
|
353
|
-
```
|
|
354
|
-
JOB_NAME: <job-name>
|
|
355
|
-
CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
If provided and the file exists, read the context document **before** reviewing the diff.
|
|
359
|
-
Use it to:
|
|
360
|
-
- Understand which architectural patterns and layers were intentionally chosen
|
|
361
|
-
- Avoid flagging deliberate deviations from the default layer model as violations
|
|
362
|
-
- Identify framework and library choices that affect what counts as a valid pattern
|
|
363
|
-
|
|
364
|
-
If absent, proceed normally — context is optional and non-blocking.
|
|
365
|
-
When in doubt about whether a pattern was intentional, use `info` severity and note the uncertainty.
|
|
351
|
+
When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
|
|
366
352
|
|
|
367
353
|
---
|
|
368
354
|
|
|
@@ -377,3 +363,16 @@ When in doubt about whether a pattern was intentional, use `info` severity and n
|
|
|
377
363
|
| "The team probably didn't intend this pattern" | Unless the context doc or a clear rule says otherwise, assume intentional; use `info` if unsure |
|
|
378
364
|
| "NestJS global module is always wrong" | `@Global()` is a violation only when used for non-global concerns; framework-provided globals are fine |
|
|
379
365
|
| "I can't determine if this is wrong without knowing the full architecture" | Use `NEEDS_CONTEXT` status and ask one specific question |
|
|
366
|
+
|
|
367
|
+
<!-- keryx:layers-block:start -->
|
|
368
|
+
## Project layers: graph, tests, wiki, memory
|
|
369
|
+
|
|
370
|
+
Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
|
|
371
|
+
|
|
372
|
+
- `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
|
|
373
|
+
- `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
|
|
374
|
+
- `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
|
|
375
|
+
- `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
|
|
376
|
+
|
|
377
|
+
In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
|
|
378
|
+
<!-- keryx:layers-block:end -->
|
|
@@ -338,20 +338,7 @@ STATUS: DONE | DONE_WITH_CONCERNS | NEEDS_CONTEXT | BLOCKED
|
|
|
338
338
|
|
|
339
339
|
## Job Context Awareness
|
|
340
340
|
|
|
341
|
-
When dispatched by `
|
|
342
|
-
|
|
343
|
-
```
|
|
344
|
-
JOB_NAME: <job-name>
|
|
345
|
-
CONTEXT_PATH: <JOBS_ROOT>/<job-name>/ai/context.md
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
If provided and the file exists, read the context document **before** running scope detection.
|
|
349
|
-
Use it to understand:
|
|
350
|
-
- Which ORM, validation library, or guard strategy was intentionally chosen
|
|
351
|
-
- Project-level architectural decisions (e.g., no repository pattern by design)
|
|
352
|
-
- Acceptance criteria to verify spec compliance
|
|
353
|
-
|
|
354
|
-
If absent, proceed normally — context is optional and non-blocking.
|
|
341
|
+
When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
|
|
355
342
|
|
|
356
343
|
---
|
|
357
344
|
|
|
@@ -364,3 +351,16 @@ If absent, proceed normally — context is optional and non-blocking.
|
|
|
364
351
|
| "The controller has some logic but it's minor" | The line is binary — logic in controller = untestable without HTTP stack |
|
|
365
352
|
| "Stack trace in response only shows in dev" | Config can be wrong in prod; treat it as blocker always |
|
|
366
353
|
| "I'll skip the migration check — it's just a column rename" | Column renames without fallback break zero-downtime deploys |
|
|
354
|
+
|
|
355
|
+
<!-- keryx:layers-block:start -->
|
|
356
|
+
## Project layers: graph, tests, wiki, memory
|
|
357
|
+
|
|
358
|
+
Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
|
|
359
|
+
|
|
360
|
+
- `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
|
|
361
|
+
- `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
|
|
362
|
+
- `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
|
|
363
|
+
- `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
|
|
364
|
+
|
|
365
|
+
In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
|
|
366
|
+
<!-- keryx:layers-block:end -->
|
|
@@ -594,22 +594,7 @@ Stop and re-read these rules if you are thinking:
|
|
|
594
594
|
|
|
595
595
|
## Job Context Awareness
|
|
596
596
|
|
|
597
|
-
When dispatched by `
|
|
598
|
-
|
|
599
|
-
```
|
|
600
|
-
JOB_NAME: <job-name>
|
|
601
|
-
CONTEXT_PATH: <JOBS_ROOT>/<job-name>/ai/context.md
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
If provided and the file exists, read the context document before starting the review. Use it to:
|
|
605
|
-
- Understand which MobX version and decorator configuration the project uses (legacy decorators vs. `makeObservable`)
|
|
606
|
-
- Identify custom base store classes or lifecycle conventions that differ from defaults
|
|
607
|
-
- Understand which accessibility standard the project targets (WCAG 2.1 AA vs. custom)
|
|
608
|
-
- Identify intentional patterns that appear to violate rules but are documented exceptions
|
|
609
|
-
- Validate findings against documented project-specific conventions
|
|
610
|
-
|
|
611
|
-
If the file does not exist or is not provided, proceed normally — context is optional and non-blocking.
|
|
612
|
-
|
|
597
|
+
When dispatched by `review-orchestrator` or `job-orchestrator`, the prompt MAY carry `JOB_NAME` and `CONTEXT_PATH: .metaproject/jobs/<job-name>/ai/context.md`. If given and the file exists, read it before you start; use it for intentional design decisions (do not flag correct library usage), acceptance criteria when there is no `issue_url`, and the severity of edge cases the team accepted. If absent, proceed normally: context is optional and non-blocking.
|
|
613
598
|
|
|
614
599
|
## Orchestrated Review Contract
|
|
615
600
|
|
|
@@ -617,3 +602,15 @@ When dispatched by `review-orchestrator`, follow the provided `reviewer-input.sc
|
|
|
617
602
|
|
|
618
603
|
---
|
|
619
604
|
|
|
605
|
+
<!-- keryx:layers-block:start -->
|
|
606
|
+
## Project layers: graph, tests, wiki, memory
|
|
607
|
+
|
|
608
|
+
Your payload may carry a `layers` block for your files: the files the graph says are affected, symbol neighbours, related tests, the wiki pages that describe the files and the memory entries for their module. It is bounded, and `truncated` names what was cut and the command that fetches the rest. When the diff alone does not settle a question, ask the project. Each command below is read-only and calls no model.
|
|
609
|
+
|
|
610
|
+
- `keryx gdgraph affected <file>`: who depends on the file. Use it before you call a change contained, and whenever a changed export, signature or behaviour may have callers outside your files.
|
|
611
|
+
- `keryx test related <file>`: the tests that cover the file. Use it before you say a behaviour is untested, and to judge whether a test would fail if the code broke.
|
|
612
|
+
- `keryx wiki ask "<q>"`: what the project wiki says a module is for and which rules bind it. Use it when the intent of the code is unclear and the diff does not state it.
|
|
613
|
+
- `keryx memory search "<q>"`: recorded lessons, decisions and known mistakes. Use it before you report a pattern the project may already have decided on, and when a failure looks like one it has seen.
|
|
614
|
+
|
|
615
|
+
In a review package, `keryx gdgraph affected <file> --data-dir <package>/layers/graph` reads the graph built at the PR head; the tracked graph may be from another commit. A finding still rests on the code you read: what a layer says is a lead, not evidence. If a layer is empty or a command fails, say so in the report instead of guessing.
|
|
616
|
+
<!-- keryx:layers-block:end -->
|