Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion packages/cli/src/args/help.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,13 @@ describe("cli/args/help", () => {
"`wg <archive-uri>/index sync` builds or repairs local `index.db` cache from artifacts",
);
expect(renderHelpTopicText("readiness")).toContain(
"Free archive query can lazy-sync the cache on first use",
"Archive-level query can create a missing cache from current artifacts on first use",
);
expect(renderHelpTopicText("readiness")).toContain(
"Broad query is grouped by result type first",
);
expect(renderHelpTopicText("readiness")).toContain(
"FTS, Dense, and Hybrid ranking affect ordering inside those result groups",
);
expect(renderHelpTopicText("readiness")).toContain(
"wg <archive-uri>/index sync --help",
Expand Down Expand Up @@ -572,6 +578,15 @@ describe("cli/args/help", () => {
expect(
renderUriHelpText("job-collection-scope", "wikg://local/job"),
).toContain("generation jobs can consume model/runtime cost");
expect(
renderUriHelpText("job-collection-scope", "wikg://local/job"),
).toContain("Job list does not support `--jsonl`");
expect(
renderUriHelpText(
"chapter-summary-object",
"wikg://book.wikg/chapter/part/summary",
),
).toContain("does not guarantee the prose answers every question");
expect(
renderUriPredicateHelpText(
"job-collection-scope",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/runtime/entry-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface WikiGraphEntryRuntimeContext {
readonly stateDir?: string | undefined;
}

const DANGEROUS_RUNTIME_ENV_NAMES = [
export const DANGEROUS_RUNTIME_ENV_NAMES = [
"WIKIGRAPH_DEV",
"WIKIGRAPH_ENV_POLICY",
"WIKIGRAPH_QUEUE_DISABLE_AUTOSTART",
Expand Down
29 changes: 28 additions & 1 deletion packages/cli/src/runtime/internal-child.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
withWikiGraphCLIRuntimeContext,
type WikiGraphCLIRuntimeContext,
} from "./context.js";
import { createInternalChildCommandForTesting } from "./internal-child.js";
import {
createInternalChildCommandForTesting,
createInternalChildEnvironmentForTesting,
} from "./internal-child.js";

describe("runtime/internal-child", () => {
it("uses source worker entries from the development runtime context", async () => {
Expand Down Expand Up @@ -51,6 +54,30 @@ describe("runtime/internal-child", () => {
);
});
});

it("does not pass parent runtime override env to internal children", async () => {
await withRuntimeContext(
{
env: {
...process.env,
WIKIGRAPH_DEV: "/tmp/dev-state",
WIKIGRAPH_ENV_POLICY: "development",
WIKIGRAPH_QUEUE_DISABLE_AUTOSTART: "1",
WIKIGRAPH_STATE_DIR: "/tmp/state",
WIKIGRAPH_TEST_VALUE: "kept",
},
},
() => {
const environment = createInternalChildEnvironmentForTesting();

expect(environment.WIKIGRAPH_TEST_VALUE).toBe("kept");
expect(environment.WIKIGRAPH_DEV).toBeUndefined();
expect(environment.WIKIGRAPH_ENV_POLICY).toBeUndefined();
expect(environment.WIKIGRAPH_QUEUE_DISABLE_AUTOSTART).toBeUndefined();
expect(environment.WIKIGRAPH_STATE_DIR).toBeUndefined();
},
);
});
});

async function withRuntimeContext(
Expand Down
17 changes: 16 additions & 1 deletion packages/cli/src/runtime/internal-child.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getCLIEnv,
getCLIStateDir,
} from "./context.js";
import { DANGEROUS_RUNTIME_ENV_NAMES } from "./entry-context.js";

export type InternalChildKind = "gc-worker" | "queue-worker";

Expand All @@ -29,11 +30,15 @@ export function spawnInternalChild(
return spawn(command.command, command.args, {
cwd: getCLICwd(),
detached: options.detached === true,
env: getCLIEnv(),
env: createInternalChildEnvironment(),
stdio: options.detached === true ? "ignore" : ["ignore", "pipe", "pipe"],
});
}

export function createInternalChildEnvironmentForTesting(): NodeJS.ProcessEnv {
return createInternalChildEnvironment();
}

export async function runInternalChildJSON<T>(
kind: InternalChildKind,
options: InternalChildSpawnOptions = {},
Expand Down Expand Up @@ -110,6 +115,16 @@ function createInternalChildCommand(
};
}

function createInternalChildEnvironment(): NodeJS.ProcessEnv {
const environment = { ...getCLIEnv() };

for (const name of DANGEROUS_RUNTIME_ENV_NAMES) {
delete environment[name];
}

return environment;
}

function resolveProductionEntryPath(kind: InternalChildKind): string {
const filename = `${kind}.js`;
const distDirPath =
Expand Down
14 changes: 9 additions & 5 deletions packages/core/data/help/commands/predicate.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,18 @@ Usage:

Notes:
- This command enqueues work; it does not wait for the artifact to be built.
- A queued response means the artifact is not ready yet. Use the returned job id with `wg wikg://local/job/<job-id> watch` to follow progress.
- A queued response means the artifact is not ready yet. Use the returned job id with `{{ commandName }} wikg://local/job/<job-id> watch` to follow progress.
{% if "/index/fts" in uri %}
- FTS artifacts are local compilation work and do not call a provider.
{% else %}
- Source and summary embedding artifacts require `wikg://local/config/embeddings` and may call the configured provider.
- Direct artifact build is an explicit build request; it does not use `--accept-cost`.
- Building an embedding artifact can immediately enqueue or run provider-backed work and may incur provider cost.
{% endif %}
- Direct artifact build is an explicit build request; it does not use `--accept-cost`.
{% if "/index/embedding/summary" in uri %}
- Summary embedding artifacts require an existing non-empty chapter summary.
{% endif %}
- After artifacts change, sync the archive or library index cache before library query; free archive query can lazy-sync on first use.
- After artifacts change, sync the archive or library index cache before library query; archive-level query can create a missing archive cache from current artifacts on first use.
{% elif predicate == "add" and target.name == "chapter-collection-scope" %}
Purpose:
Add a chapter to the archive.
Expand Down Expand Up @@ -411,7 +414,8 @@ Notes:
- It reads chapter index artifacts from the archive and does not call an embeddings provider.
- If required chapter artifacts are missing, sync reports that artifact readiness problem instead of building them.
- Add `--skip-unindexed` only when you intentionally want the cache to include indexed chapters and ignore uncovered chapters.
- Free archive query can lazy-sync this cache, but explicit sync avoids the first-query delay.
- Archive-level query can create a missing cache from current artifacts on first use, but explicit sync avoids the first-query delay.
- If query reports a missing or outdated cache, run this sync command before retrying.
- With `--jsonl`, progress is emitted as line-delimited event records.
{% endif %}
{% elif predicate == "clean" and target.name == "index-object" %}
Expand All @@ -424,7 +428,7 @@ Usage:
Notes:
- This removes local `index.db` cache data only.
- It does not delete chapter index artifacts, Knowledge Graph, Reading Graph, Summary, source text, or library membership.
- Free archive query can recreate an archive cache from artifacts.
- Archive query can recreate an archive cache from artifacts when the selected scope supports lazy cache creation.
{% elif predicate == "clean" %}
Purpose:
Remove completed local generation jobs.
Expand Down
5 changes: 5 additions & 0 deletions packages/core/data/help/commands/uri.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ URI type:
Default behavior:
- `{{ commandName }} {{ uri }}` enumerates archive-level objects.
- `{{ commandName }} {{ uri }} --query <query>` applies search index retrieval across archive scopes.
- Broad query results are bucketed by object family: chapter/title hits, graph objects, chunks, then text streams.
- Query is strict by default; add `--skip-unindexed` only to intentionally search indexed chapters and ignore uncovered chapters.

Use when:
Expand Down Expand Up @@ -43,6 +44,7 @@ URI type:
Default behavior:
- `{{ commandName }} {{ uri }}` enumerates objects inside this chapter subtree.
- `{{ commandName }} {{ uri }} --query <query>` applies search index retrieval inside this chapter subtree.
- Broad query results are bucketed by object family: chapter/title hits, graph objects, chunks, then text streams.
- Query is strict by default; add `--skip-unindexed` only to intentionally search indexed chapters and ignore uncovered chapters.
- Use `--depth 0` to restrict the scope to this chapter only; `--depth 1` includes direct children.
- The path in this URI is the public CLI handle for the chapter; internal chapter ids are not command targets.
Expand Down Expand Up @@ -135,6 +137,7 @@ Default behavior:
- Summary range fragments such as `#4..8` read sentence numbers 4 through 8, inclusive.
- Range sentence numbers are 1-based. `#1` is the first sentence; `#1..2` is the first two sentences.
- Whole summary reads are plain text streams and do not support `--json`; summary range fragments are structured range objects and support `--json`.
- Summary readiness means a summary object exists and is current for the chapter source. It does not guarantee the prose answers every question about the chapter.

Use when:
- You need compact readable prose before tracing source evidence.
Expand Down Expand Up @@ -186,6 +189,7 @@ Default behavior:
Use when:
- You need to build or delete one chapter-level index artifact stored in the `.wikg` archive.
- Use `/index/fts` for lexical retrieval, `/index/embedding/source` for Dense source retrieval, or `/index/embedding/summary` for Dense summary retrieval.
- Build enqueues a local job; read the returned job status or watch the job before assuming the artifact is ready.
{% elif target.name == "chunk-object" %}
URI type:
Chunk object
Expand Down Expand Up @@ -247,6 +251,7 @@ URI type:

Default behavior:
- `{{ commandName }} {{ uri }}` shows local generation jobs.
- Use `--json` for a machine-readable job list. Job list does not support `--jsonl`; `watch --jsonl` is the streaming job interface.

Use when:
- You need to inspect, add, or clean local generation jobs.
Expand Down
7 changes: 6 additions & 1 deletion packages/core/data/help/topics/readiness.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ Archive index readiness:
Cache behavior:
`{{ commandName }} <archive-uri>/index sync` builds or repairs local `index.db` cache from artifacts.
Sync does not build missing artifacts and does not call an embeddings provider.
Free archive query can lazy-sync the cache on first use, but explicit sync avoids the first-query delay.
Archive-level query can create a missing cache from current artifacts on first use, but explicit sync avoids the first-query delay.
If query reports a missing or outdated cache, run `{{ commandName }} <archive-uri>/index sync`; library query always requires a current library cache.
`{{ commandName }} <archive-uri>/index clean` deletes only the local cache.

Query behavior:
FTS artifact only: FTS query.
Source embedding artifact only: semantic/Dense-only query.
Both artifacts: Hybrid query with automatic fusion.
Broad query is grouped by result type first: chapter/title, object, chunk, then source/summary text.
FTS, Dense, and Hybrid ranking affect ordering inside those result groups and evidence-backed object ranking; they do not flatten the type groups into one global rerank.
Missing both FTS and source embedding for any content chapter in scope: ordinary query fails.
Add `--skip-unindexed` to a scope query, `related --query`, or `evidence --query` only when you want to search indexed chapters and ignore uncovered chapters.
Results produced with `--skip-unindexed` are intentionally partial; inspect coverage before treating absent chapters as negative evidence.
Summary embedding artifacts are for summary semantic retrieval and are not the minimum requirement for ordinary source query.

Commands:
Expand Down Expand Up @@ -142,6 +146,7 @@ WikiSpine readiness:
How to choose:
- Need lexical retrieval: build chapter FTS artifacts, then sync cache if you do not want lazy sync.
- Need semantic retrieval: configure embeddings, build source embedding artifacts, then sync cache.
- Need both lexical and semantic retrieval: build both FTS and source embedding artifacts, then sync the archive index cache if it already exists or query reports it outdated; query can create a missing archive cache and chooses Hybrid automatically once the cache is current.
- Need searchable retrieval across a managed folder: sync the library index cache.
- Need to intentionally drop local cache: clean index cache; artifacts remain in the archive.
- Need generated Reading Graph or summaries: configure LLM and use local jobs.
Expand Down
2 changes: 2 additions & 0 deletions packages/core/data/help/topics/uri.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Scope URIs:
A chapter URI used as a scope covers that chapter's full subtree by default.
Query is strict by default: every chapter in scope must have a current FTS artifact or source embedding artifact.
Add `--skip-unindexed` only when you intentionally want to search indexed chapters and ignore uncovered chapters.
Broad query is grouped by result type before ranking within each group. Use `/chunk`, `/entity`, or `/triple` lenses when you want one object family instead of the mixed broad result. Query an archive or chapter scope to find source or summary text, then read the returned `/source` or `/summary` object.
Search uses FTS-only, Dense-only, or Hybrid automatically from the current artifacts and index cache; use `{{ commandName }} help readiness` to inspect what must exist.
Add `--depth <N>` to limit chapter subtree expansion:
- no `--depth`: full subtree
- `--depth 0`: only the current chapter, or root-level chapters for `<archive-uri>/chapter`
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/retrieval/query/archive-view/search/buckets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import {
assertSearchCursorTypesMatch,
createEntitySearchCacheInput,
createSentenceEvidenceSearchCacheInput,
} from "./cache-input.js";
import { findEntities, findTriples } from "../find.js";
import {
Expand Down Expand Up @@ -297,7 +298,7 @@ async function populateObjectBucketCaches(
: { embeddingProvider: options.embeddingProvider }),
match: parseFindMatch(session.match),
objectHitLimit: SEARCH_INDEX_FTS_HIT_LIMIT,
textHitLimit: 0,
textHitLimit: SEARCH_INDEX_FTS_HIT_LIMIT,
types: null,
}),
]);
Expand All @@ -309,11 +310,24 @@ async function populateObjectBucketCaches(
structuredHits,
indexed,
);
const sentenceCacheInput = await createSentenceEvidenceSearchCacheInput(
document,
indexed,
options,
);

await populateSearchSessionObjectCaches({
entityHits: entityCacheInput.entityHits,
evidenceEvents: entityCacheInput.evidenceEvents,
chunkHits: sentenceCacheInput.chunkHits,
entityHits: [
...entityCacheInput.entityHits,
...sentenceCacheInput.entityHits,
],
evidenceEvents: [
...entityCacheInput.evidenceEvents,
...sentenceCacheInput.evidenceEvents,
],
sessionId: session.sessionId,
tripleHits: sentenceCacheInput.tripleHits,
});
}

Expand Down
Loading
Loading