From e625b46f82e8ba24308f88703a5631c76610c3d3 Mon Sep 17 00:00:00 2001 From: theDakshJaitly Date: Tue, 8 Sep 2026 01:19:19 +0530 Subject: [PATCH 01/19] fix(grounding): require explicit baseline acceptance --- .mex/patterns/durable-change-signal.md | 31 ++- src/drift/checkers/grounding.ts | 6 + src/graph/grounding.ts | 2 +- src/graph/runtime.ts | 354 ++++++++++++++++++------- src/sync/brief-builder.ts | 13 +- src/sync/index.ts | 78 +++++- test/graph-grounding-body-hash.test.ts | 246 ++++++++++++++++- test/graph-grounding.test.ts | 10 + test/graph-integration.test.ts | 12 +- test/setup-grounding-e2e.test.ts | 12 +- 10 files changed, 626 insertions(+), 138 deletions(-) diff --git a/.mex/patterns/durable-change-signal.md b/.mex/patterns/durable-change-signal.md index bedaa2b0..ec1f4667 100644 --- a/.mex/patterns/durable-change-signal.md +++ b/.mex/patterns/durable-change-signal.md @@ -14,12 +14,12 @@ edges: condition: "when the value also lives in the graph database" - target: "context/conventions.md" condition: "when verifying the change" -last_updated: 2026-09-03 +last_updated: 2026-09-07 mex: id: mx_01M1M0CJK5ZTSHCDDWB3NTSEBF type: pattern status: promoted - revision: 4 + revision: 5 title: durable-change-signal grounds_to: - node: function:fa9a6935ad14990f545c7802e4ecbc0a @@ -73,10 +73,12 @@ Two distinct kinds of value, and the difference decides where each one lives: scaffold in the world lacks it, and a required field turns each of them into a parse error. Mirror the wiki lane's key name and placement so both writers produce one shape rather than two conventions. -3. Populate it at every write site, from a value the graph produced. The setup - and sync path converges through +3. Populate it during initial capture or explicitly accepted renewal, from a + value the graph produced. The setup and sync path converges through [`captureGroundingBaselines()`](mex://function:fa9a6935ad14990f545c7802e4ecbc0a). - Never let a caller supply one — a hash an agent can invent is not evidence. + A reviewed replacement must match the exact current graph fingerprint/body + hash and the reviewed document bytes. A hash an agent can invent is not + evidence, and a successful agent exit is not acceptance. 4. **Change the readers in the same commit.** A field nothing reads is inert, and a fix that ships only the write half looks complete and does nothing. Grep for every consumer of the old source of truth before you start. @@ -91,10 +93,15 @@ Two distinct kinds of value, and the difference decides where each one lives: canonical value**, not a second store of a fact. Otherwise the next reader deletes it as a duplicate — and it often carries something Markdown has no business holding, such as the body text a drift review needs for a diff. -7. Backfill by default; re-baseline only through an explicitly authorized sync - or when a caller is deliberately re-pointing the record at current code. A - value that merely **differs** is the finding; overwriting it erases the - evidence and reports fresh on the next run. +7. Initial capture may establish a missing baseline. Legacy backfill must use + the prior cached baseline when one exists, preserving the old body as well + as its hash. Renew only the specific entries accepted after a concrete + review; unrelated groundings must remain untouched. A value that merely + **differs** is the finding, not permission to replace it. +8. Keep pointer repair separate from accepting behavior. MOVED repairs carry + forward earlier change evidence, and the reader compares that evidence to + the resolved node. A rename may therefore still need review. Do not erase + that review signal merely because identity reconciliation succeeded. ## Verify @@ -102,6 +109,12 @@ Two distinct kinds of value, and the difference decides where each one lives: still fire. This is the whole point, and it is the only test that proves it. - A record written before the field existed must still parse, still validate, still warn, and still behave exactly as it did against a live index. +- A no-op agent that exits successfully must preserve existing hashes, + fingerprints, cached old code, and drift. Include literal-only code changes, + which can leave fingerprints identical. +- A declined or stale review must preserve the baseline. An accepted review + must affect only its selected grounding, with document and source facts + revalidated before publication. - Confirm the new tests actually fail on the pre-fix tree. Restore the source files from the base commit and re-run; a test that passes both ways is a backward-compatibility pin, not a proof of the fix, and should be labelled as diff --git a/src/drift/checkers/grounding.ts b/src/drift/checkers/grounding.ts index 4d2d7c2b..cd488c3a 100644 --- a/src/drift/checkers/grounding.ts +++ b/src/drift/checkers/grounding.ts @@ -79,6 +79,12 @@ export function makeGroundingChecker( if (!baseline) continue; const resolution = reconciler.reconcile(grounding.node, baseline); if (resolution.kind === "MOVED") { + const moved = graph.getNode(resolution.nodeId); + const baselineBodyHash = grounding.bodyHash ?? baselineSource?.bodyHash; + if (moved && baselineBodyHash !== undefined && moved.bodyHash !== baselineBodyHash) { + issues.push(issue("GROUNDING_DRIFT", "warning", source, + `Grounded node body changed: ${grounding.node}; candidate: ${resolution.nodeId}`)); + } grounding.node = resolution.nodeId; const movedFingerprint = capabilities.getFingerprint?.(resolution.nodeId); if (movedFingerprint) grounding.fingerprint = serializeFingerprint(movedFingerprint); diff --git a/src/graph/grounding.ts b/src/graph/grounding.ts index 95938b9c..917c86dc 100644 --- a/src/graph/grounding.ts +++ b/src/graph/grounding.ts @@ -22,7 +22,7 @@ // Tier-1 hit + body unchanged -> clean (no issue) // Tier-1 hit + body_hash moved -> WARNING (GROUNDING_DRIFT) // Tier-1 miss -> reconcile: -// MOVED -> clean, rebind grounds_to (no issue) +// MOVED -> rebind identity; WARNING if the accepted body hash differs // AMBIGUOUS -> WARNING (GROUNDING_AMBIGUOUS) + candidate id // GONE -> ERROR (GROUNDING_GONE) diff --git a/src/graph/runtime.ts b/src/graph/runtime.ts index 73c3eb2e..16a4d407 100644 --- a/src/graph/runtime.ts +++ b/src/graph/runtime.ts @@ -1,5 +1,6 @@ -import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs"; -import { relative, resolve } from "node:path"; +import { createHash, randomUUID } from "node:crypto"; +import { closeSync, constants, existsSync, fstatSync, openSync, readFileSync, readSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs"; +import { isAbsolute, relative, resolve } from "node:path"; import { globSync } from "glob"; import type { MexConfig, Grounding } from "../types.js"; import { extractGroundings, findMexAnchors, rewriteMexAnchor, writeGroundings } from "../markdown.js"; @@ -9,6 +10,7 @@ import type { GraphEngine } from "./engine.js"; import { GRAPH_CORPUS_GLOB_OPTIONS, GRAPH_CORPUS_IGNORE_GLOBS, + GRAPH_CORPUS_LIMITS, GRAPH_SUPPORTED_SOURCE_GLOB, } from "./corpus-policy.js"; import { openGraphDatabase } from "./db/database.js"; @@ -47,11 +49,30 @@ export interface GroundingBaselineCaptureResult { } export interface GroundingBaselineCaptureOptions { - /** Sync may normalize an agent's stale fingerprint to the current graph fact. */ - updateFingerprints?: boolean; + /** Renew only these explicitly reviewed entries, after revalidating their exact facts. */ + acceptedGroundings?: readonly GroundingBaselineAcceptance[]; warn?: (message: string) => void; } +/** An in-process review bound to one document revision and one exact graph fact. */ +export interface GroundingBaselineAcceptance { + scaffoldFile: string; + nodeId: string; + contentHash: string; + fingerprint: string; + bodyHash: string; +} + +export interface GroundingBaselineReview { + acceptance: GroundingBaselineAcceptance; + content: string; + oldBody: string | null; + newBody: string; +} + +const GROUNDING_REVIEW_MAX_BYTES = 64 * 1024; +const GROUNDING_REVIEW_MAX_ENTRIES = 64; + export interface ReadOnlyGroundingRuntimeResult { graphStatus: GraphStatus; runtime: GroundingRuntime | null; @@ -224,15 +245,11 @@ export async function captureGroundingBaselines( return { captured: 0, skipped: 0 }; } try { - const scaffoldFiles = globSync("**/*.md", { - cwd: config.scaffoldRoot, - absolute: true, - nodir: true, - }); - return refreshGroundingBaselines(config, scaffoldFiles, runtime, { - ...options, - updateFingerprints: options.updateFingerprints ?? false, - }); + const scaffoldFiles = options.acceptedGroundings === undefined + ? globSync("**/*.md", { cwd: config.scaffoldRoot, absolute: true, nodir: true }) + : [...new Set(options.acceptedGroundings.map((entry) => + resolveGroundingReviewFile(config, entry.scaffoldFile)))]; + return refreshGroundingBaselines(config, scaffoldFiles, runtime, options); } finally { runtime.close(); } @@ -261,20 +278,23 @@ export function findChangedSourceFiles(projectRoot: string, db: SqliteDatabase): return [...new Set(changed)].sort(); } -/** - * Move a grounding's body hash onto the node it was just rebound to. - * - * Only called on a confirmed rebind, where identity has already been - * re-established by fingerprint and the entity now points at a different node. - * The old hash describes a symbol this grounding no longer names, so carrying - * it forward would report drift on every rename — a symbol's name is part of - * its body. Dropping the key instead would be worse: the grounding would fall - * back to the structural comparator and stop detecting content drift for good. - * - * A node the graph cannot produce a hash for leaves the grounding as it was. - */ -function rebindBodyHash(grounding: Grounding, bodyHash: string | null): void { - if (bodyHash !== null) grounding.bodyHash = bodyHash; +/** Identity repair moves the old evidence; it does not accept the new body. */ +function moveGroundingBaseline( + scaffoldFile: string, + oldId: string, + newId: string, + runtime: GroundingRuntime, + pendingMoves: Map, + grounding?: Grounding, +): void { + const previous = runtime.fingerprints.getGroundedSource(scaffoldFile, oldId); + if (grounding && grounding.bodyHash === undefined && previous) { + grounding.bodyHash = previous.bodyHash; + } + const destination = runtime.fingerprints.getGroundedSource(scaffoldFile, newId); + if (previous && (destination?.nodeId !== newId || (grounding && grounding.bodyHash === previous.bodyHash))) { + pendingMoves.set(oldId, { previous, newId }); + } } /** Persist only high-confidence MOVED repairs. AMBIGUOUS/GONE remain for the agent. */ @@ -285,20 +305,21 @@ export function persistMovedGroundings( ): number { let moved = 0; for (const filePath of scaffoldFiles) { - const content = readFileSync(filePath, "utf-8"); + const content = readBoundedText(filePath, GRAPH_CORPUS_LIMITS.maxSourceFileBytes); const groundings = extractGroundings(content); const scaffoldFile = relative(config.projectRoot, filePath).replaceAll("\\", "/"); let dirty = false; + const pendingMoves = new Map(); for (const grounding of groundings) { const aliasedNode = runtime.graph.getNode(grounding.node); if (aliasedNode) { if (aliasedNode.id === grounding.node) continue; + if (groundings.some((other) => other !== grounding && other.node === aliasedNode.id)) continue; const oldId = grounding.node; grounding.node = aliasedNode.id; const fingerprint = runtime.reconciler.getFingerprint(aliasedNode.id); if (fingerprint) grounding.fingerprint = serializeFingerprint(fingerprint); - rebindBodyHash(grounding, saveCurrentBaseline(config, scaffoldFile, grounding.node, grounding.fingerprint, runtime)); - runtime.fingerprints.deleteGroundedSource(scaffoldFile, oldId); + moveGroundingBaseline(scaffoldFile, oldId, grounding.node, runtime, pendingMoves, grounding); dirty = true; moved += 1; continue; @@ -309,12 +330,12 @@ export function persistMovedGroundings( if (!baseline) continue; const resolution = runtime.reconciler.reconcile(grounding.node, baseline); if (resolution.kind !== "MOVED") continue; + if (groundings.some((other) => other !== grounding && other.node === resolution.nodeId)) continue; const oldId = grounding.node; grounding.node = resolution.nodeId; const fingerprint = runtime.reconciler.getFingerprint(resolution.nodeId); if (fingerprint) grounding.fingerprint = serializeFingerprint(fingerprint); - rebindBodyHash(grounding, saveCurrentBaseline(config, scaffoldFile, grounding.node, grounding.fingerprint, runtime)); - runtime.fingerprints.deleteGroundedSource(scaffoldFile, oldId); + moveGroundingBaseline(scaffoldFile, oldId, grounding.node, runtime, pendingMoves, grounding); dirty = true; moved += 1; } @@ -325,6 +346,9 @@ export function persistMovedGroundings( const aliasedNode = runtime.graph.getNode(anchor.nodeId); if (aliasedNode) { if (aliasedNode.id === anchor.nodeId) continue; + if (!groundings.some((entry) => entry.node === aliasedNode.id)) { + moveGroundingBaseline(scaffoldFile, anchor.nodeId, aliasedNode.id, runtime, pendingMoves); + } anchoredContent = rewriteMexAnchor(anchoredContent, anchor, aliasedNode.id); moved += 1; continue; @@ -335,10 +359,19 @@ export function persistMovedGroundings( if (!baseline) continue; const resolution = runtime.reconciler.reconcile(anchor.nodeId, baseline); if (resolution.kind !== "MOVED") continue; + if (!groundings.some((entry) => entry.node === resolution.nodeId)) { + moveGroundingBaseline(scaffoldFile, anchor.nodeId, resolution.nodeId, runtime, pendingMoves); + } anchoredContent = rewriteMexAnchor(anchoredContent, anchor, resolution.nodeId); moved += 1; } - if (anchoredContent !== content) writeFileSync(filePath, anchoredContent, "utf-8"); + if (anchoredContent !== content) { + replaceGroundingDocument(config, filePath, content, anchoredContent, GRAPH_CORPUS_LIMITS.maxSourceFileBytes); + for (const [oldId, { previous, newId }] of pendingMoves) { + runtime.fingerprints.saveGroundedSource({ ...previous, nodeId: newId }); + runtime.fingerprints.deleteGroundedSource(scaffoldFile, oldId); + } + } } return moved; } @@ -420,89 +453,183 @@ function snapshotAnchorFingerprints(config: MexConfig, store: FingerprintStore): return snapshots; } -/** Close the sync loop after an agent pass by refreshing ids' fingerprints and snapshots. */ +/** Initialize missing baselines, or renew only exact entries explicitly reviewed by the caller. */ export function refreshGroundingBaselines( config: MexConfig, scaffoldFiles: readonly string[], runtime: GroundingRuntime, options: GroundingBaselineCaptureOptions = {}, ): GroundingBaselineCaptureResult { + const accepted = options.acceptedGroundings; + if (accepted && accepted.length > GROUNDING_REVIEW_MAX_ENTRIES) { + throw new Error(`Grounding review is limited to ${GROUNDING_REVIEW_MAX_ENTRIES} entries.`); + } let captured = 0; let skipped = 0; for (const filePath of scaffoldFiles) { - const content = readFileSync(filePath, "utf-8"); + const readLimit = accepted === undefined ? GRAPH_CORPUS_LIMITS.maxSourceFileBytes : GROUNDING_REVIEW_MAX_BYTES; + const content = readBoundedText(filePath, readLimit); const groundings = extractGroundings(content); const anchors = findMexAnchors(content); if (groundings.length === 0 && anchors.length === 0) continue; const scaffoldFile = relative(config.projectRoot, filePath).replaceAll("\\", "/"); let dirty = false; + const pendingBaselines: GroundedSource[] = []; const groundingByNode = new Map(groundings.map((grounding) => [grounding.node, grounding])); const nodeIds = new Set([ ...groundingByNode.keys(), ...anchors.map((anchor) => anchor.nodeId), ]); for (const nodeId of nodeIds) { + const acceptance = accepted?.find((entry) => entry.scaffoldFile === scaffoldFile && entry.nodeId === nodeId); + // A selected renewal must not initialize or change any unselected entry. + if (accepted !== undefined && acceptance === undefined) continue; const grounding = groundingByNode.get(nodeId); + const previous = runtime.fingerprints.getGroundedSource(scaffoldFile, nodeId); + if (accepted === undefined && grounding && grounding.bodyHash === undefined && previous) { + // Legacy backfill preserves the historical baseline, even if code has changed. + grounding.bodyHash = previous.bodyHash; + dirty = true; + } const fingerprint = runtime.reconciler.getFingerprint(nodeId); - if (!fingerprint || !runtime.graph.getNode(nodeId)) { + const node = runtime.graph.getNode(nodeId); + if (!fingerprint || node?.id !== nodeId || !node.bodyHash) { skipped += 1; options.warn?.(`Skipped grounding baseline for unavailable node ${nodeId} in ${scaffoldFile}.`); continue; } const serialized = serializeFingerprint(fingerprint); - if (grounding && grounding.fingerprint !== serialized) { - if (options.updateFingerprints === false) { + if (acceptance) { + if (!grounding + || resolveGroundingReviewFile(config, scaffoldFile) !== resolve(filePath) + || acceptance.contentHash !== hashText(content) + || acceptance.fingerprint !== serialized + || acceptance.bodyHash !== node.bodyHash) { skipped += 1; - options.warn?.(`Skipped grounding baseline for changed node ${nodeId} in ${scaffoldFile}.`); + options.warn?.(`Grounding review changed for ${nodeId} in ${scaffoldFile}; review it again.`); + continue; + } + } else { + const baselineHash = grounding?.bodyHash ?? previous?.bodyHash; + if ((grounding && grounding.fingerprint !== serialized) + || (baselineHash !== undefined && baselineHash !== node.bodyHash)) { + skipped += 1; + options.warn?.(`Preserved changed grounding ${nodeId} in ${scaffoldFile}; explicit review is required.`); continue; } - grounding.fingerprint = serialized; - dirty = true; } - const bodyHash = saveCurrentBaseline(config, scaffoldFile, nodeId, serialized, runtime); - if (bodyHash === null) { + + // The old body is evidence too. Never replace it with current code merely + // because a structural fingerprint matches or an agent exited cleanly. + const baseline = currentBaseline(config, scaffoldFile, nodeId, serialized, runtime); + if (baseline === null) { skipped += 1; options.warn?.(`Skipped grounding baseline for non-body node ${nodeId} in ${scaffoldFile}.`); continue; } - captured += 1; - - // Commit the change signal alongside the identity signal, so it survives - // a `graph rebuild` and travels to a teammate who clones. Two cases only: - // - // - **backfill**, when Markdown carries no hash at all. This asserts - // nothing new — the `_mex_grounded_source` row written a line above - // already records exactly this value, from exactly this moment. It - // only makes it durable. - // - **re-baseline**, when the caller has not forbidden updates. That is - // the post-authoring routine `mex sync` runs after an agent repairs - // the prose: the entity now describes the current code, so the - // baseline has to move with it or drift never clears. - // - // `updateFingerprints === false` — what `mex ground` and setup pass — is - // the read-only posture, and there a hash that merely *differs* is left - // alone. That difference is drift, it is the finding, and overwriting it - // would erase the evidence and report `fresh` on the next run. - // - // **The authorization is the caller's flag, never whether the - // fingerprint moved.** Gating this on a fingerprint change was the first - // attempt and it was wrong in the one case that matters: editing a - // constant changes the body and leaves the fingerprint identical, by - // construction, which is the entire reason a body hash exists. The - // re-baseline then never fired and drift was permanent. Using the - // identity signal to decide a change question is the coupling this field - // exists to break — including here, in the writer. - const mayRebaseline = options.updateFingerprints !== false; - if (grounding && (grounding.bodyHash === undefined || mayRebaseline) && grounding.bodyHash !== bodyHash) { - grounding.bodyHash = bodyHash; + pendingBaselines.push(baseline); + if (grounding && acceptance && grounding.fingerprint !== serialized) { + grounding.fingerprint = serialized; dirty = true; } + if (grounding && (grounding.bodyHash === undefined || acceptance) && grounding.bodyHash !== baseline.bodyHash) { + grounding.bodyHash = baseline.bodyHash; + dirty = true; + } + } + if (readBoundedText(filePath, readLimit) !== content) { + skipped += pendingBaselines.length; + options.warn?.(`Grounding document ${scaffoldFile} changed during capture; review it again.`); + continue; + } + if (pendingBaselines.some((entry) => currentBaseline(config, scaffoldFile, entry.nodeId, entry.fingerprint, runtime)?.bodyHash !== entry.bodyHash)) { + skipped += pendingBaselines.length; + options.warn?.(`Grounding source changed during capture for ${scaffoldFile}; review it again.`); + continue; } - if (dirty) writeFileSync(filePath, writeGroundings(content, groundings), "utf-8"); + if (readBoundedText(filePath, readLimit) !== content) { + skipped += pendingBaselines.length; + options.warn?.(`Grounding document ${scaffoldFile} changed before publication; review it again.`); + continue; + } + if (dirty) replaceGroundingDocument(config, filePath, content, writeGroundings(content, groundings), readLimit); + // Markdown is authoritative. A failed document publication leaves its old + // cache untouched; a cache failure after publication cannot erase history. + for (const baseline of pendingBaselines) { + const previous = runtime.fingerprints.getGroundedSource(scaffoldFile, baseline.nodeId); + if (previous?.bodyHash !== baseline.bodyHash || previous.fingerprint !== baseline.fingerprint) { + runtime.fingerprints.saveGroundedSource(baseline); + } + } + captured += pendingBaselines.length; } return { captured, skipped }; } +/** Produce a bounded review from current graph facts without changing a baseline. */ +export function groundingReviewNodeIds(config: MexConfig, scaffoldFile: string): string[] | null { + const filePath = resolveGroundingReviewFile(config, scaffoldFile); + if (statSync(filePath).size > GROUNDING_REVIEW_MAX_BYTES) return null; + const content = readBoundedText(filePath, GROUNDING_REVIEW_MAX_BYTES); + return [...new Set(extractGroundings(content).map((entry) => entry.node))]; +} + +/** Produce a bounded review from current graph facts without changing a baseline. */ +export function previewGroundingBaseline( + config: MexConfig, + scaffoldFile: string, + nodeId: string, + runtime: GroundingRuntime, +): GroundingBaselineReview | null { + const filePath = resolveGroundingReviewFile(config, scaffoldFile); + if (statSync(filePath).size > GROUNDING_REVIEW_MAX_BYTES) return null; + const content = readBoundedText(filePath, GROUNDING_REVIEW_MAX_BYTES); + const matching = extractGroundings(content).filter((entry) => entry.node === nodeId); + if (matching.length !== 1) return null; + const grounding = matching[0]!; + const node = runtime.graph.getNode(nodeId); + const fingerprint = runtime.reconciler.getFingerprint(nodeId); + if (node?.id !== nodeId || !node.bodyHash || !fingerprint) return null; + const serialized = serializeFingerprint(fingerprint); + const previous = runtime.fingerprints.getGroundedSource(scaffoldFile, nodeId); + if ((grounding.bodyHash ?? previous?.bodyHash) === node.bodyHash + && grounding.fingerprint === serialized) return null; + const newBody = readNodeBody(config.projectRoot, node.filePath, node.startLine, node.endLine); + const oldBody = previous && (grounding.bodyHash === undefined || grounding.bodyHash === previous.bodyHash) + && hashBody(previous.source) === previous.bodyHash ? previous.source : null; + if (hashBody(newBody) !== node.bodyHash + || Buffer.byteLength(newBody) > GROUNDING_REVIEW_MAX_BYTES + || (oldBody !== null && Buffer.byteLength(oldBody) > GROUNDING_REVIEW_MAX_BYTES)) return null; + return { + acceptance: { scaffoldFile, nodeId, contentHash: hashText(content), fingerprint: serialized, bodyHash: node.bodyHash }, + content, + oldBody, + newBody, + }; +} + +function resolveGroundingReviewFile(config: MexConfig, scaffoldFile: string): string { + const filePath = resolve(config.projectRoot, scaffoldFile); + const scaffoldRelative = relative(realpathSync(config.scaffoldRoot), realpathSync(filePath)); + if (isAbsolute(scaffoldFile) + || relative(config.projectRoot, filePath).replaceAll("\\", "/") !== scaffoldFile + || scaffoldRelative === "" || scaffoldRelative === ".." || scaffoldRelative.startsWith("../") + || scaffoldRelative.startsWith("..\\") || isAbsolute(scaffoldRelative) + || !filePath.endsWith(".md")) { + throw new Error("Grounding review requires a Markdown file contained in the scaffold."); + } + return filePath; +} + +function hashText(text: string): string { + return createHash("sha256").update(text).digest("hex"); +} + +/** Same normalized body bytes used by the graph; never bless a changed source read. */ +function hashBody(source: string): string { + return hashText(source.replace(/\s+/g, " ").trim()); +} + export function groundingPromptContext( config: MexConfig, scaffoldFile: string, @@ -513,6 +640,9 @@ export function groundingPromptContext( const baseline = runtime.reconciler.getGroundedSource(scaffoldFile, nodeId); const current = runtime.graph.getNode(candidateId ?? nodeId); if (!baseline || !current) return null; + const grounding = extractGroundings(readBoundedText(resolve(config.projectRoot, scaffoldFile), GRAPH_CORPUS_LIMITS.maxSourceFileBytes)) + .find((entry) => entry.node === nodeId); + if (grounding?.bodyHash !== undefined && grounding.bodyHash !== baseline.bodyHash) return null; return { nodeId, oldBody: baseline.source, @@ -521,41 +651,73 @@ export function groundingPromptContext( }; } -/** - * Cache the node's current body beside its hash, and hand the hash back. - * - * The row it writes into `_mex_grounded_source` is a **cache of a canonical - * value, not a second store of a fact.** `.mex/graph.db` is gitignored and - * disposable by invariant — `mex graph rebuild` is offered as a routine repair - * — so anything held only here is gone on the next rebuild and never reaches a - * teammate who clones. The durable copy of `bodyHash` is the one the callers - * write into the Markdown grounding, which is why this returns it rather than a - * bare boolean. Keep the row: it also carries the body *text*, which drift - * review needs for a diff and Markdown has no business holding. - * - * Returns the body hash on success, or null for a node the graph does not hold - * or that has no body — the same condition the boolean used to report. - */ -function saveCurrentBaseline( +/** Stage a graph-verified cache row. The caller publishes Markdown before saving it. */ +function currentBaseline( config: MexConfig, scaffoldFile: string, nodeId: string, fingerprint: string, runtime: GroundingRuntime, -): string | null { +): GroundedSource | null { const node = runtime.graph.getNode(nodeId); if (!node?.bodyHash) return null; - const source: GroundedSource = { + const body = readNodeBody(config.projectRoot, node.filePath, node.startLine, node.endLine); + if (hashBody(body) !== node.bodyHash) return null; + return { scaffoldFile, nodeId: node.id, - source: readNodeBody(config.projectRoot, node.filePath, node.startLine, node.endLine), + source: body, bodyHash: node.bodyHash, fingerprint, }; - runtime.fingerprints.saveGroundedSource(source); - return node.bodyHash; } function readNodeBody(root: string, filePath: string, startLine: number, endLine: number): string { - return readFileSync(resolve(root, filePath), "utf-8").split("\n").slice(startLine - 1, endLine).join("\n"); + return readBoundedText(resolve(root, filePath), GRAPH_CORPUS_LIMITS.maxSourceFileBytes) + .split("\n").slice(startLine - 1, endLine).join("\n"); +} + +function readBoundedText(filePath: string, maxBytes: number): string { + const fd = openSync(filePath, constants.O_RDONLY | constants.O_NOFOLLOW); + try { + const before = fstatSync(fd, { bigint: true }); + if (!before.isFile() || before.size > BigInt(maxBytes)) throw new Error("Grounding file exceeds its read limit."); + const bytes = Buffer.alloc(Number(before.size) + 1); + let length = 0; + while (length < bytes.length) { + const read = readSync(fd, bytes, length, bytes.length - length, null); + if (read === 0) break; + length += read; + } + const after = fstatSync(fd, { bigint: true }); + if (length !== Number(before.size) || before.size !== after.size + || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs) { + throw new Error("Grounding file changed during its read."); + } + return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length)); + } finally { + closeSync(fd); + } +} + +function replaceGroundingDocument( + config: MexConfig, + filePath: string, + previous: string, + next: string, + readLimit: number, +): void { + const scaffoldFile = relative(config.projectRoot, filePath).replaceAll("\\", "/"); + resolveGroundingReviewFile(config, scaffoldFile); + const temporary = `${filePath}.grounding-${randomUUID()}.tmp`; + try { + writeFileSync(temporary, next, { flag: "wx", mode: statSync(filePath).mode & 0o777 }); + resolveGroundingReviewFile(config, scaffoldFile); + if (readBoundedText(filePath, readLimit) !== previous) { + throw new Error("Grounding document changed before publication; review it again."); + } + renameSync(temporary, filePath); + } finally { + try { unlinkSync(temporary); } catch { /* A successful rename consumed it. */ } + } } diff --git a/src/sync/brief-builder.ts b/src/sync/brief-builder.ts index e68aad39..c1f3f9f1 100644 --- a/src/sync/brief-builder.ts +++ b/src/sync/brief-builder.ts @@ -53,18 +53,20 @@ function buildGroundingRepairInstructions(targets: SyncTarget[]): string { return `GROUNDING REPAIR — repair the prose and both pointer mechanisms together: Use the code graph for implementation context; do not sample source files. Start -with \`mex graph scope ""\`, then use \`mex graph query +with \`mex graph scope "" --fingerprint\`, then use \`mex graph query where-defined \`, who-calls/what-calls, or \`mex impact \` to resolve exact behavior and candidates. READ BROAD, GROUND TIGHT: read the whole useful neighborhood, but ground only functions/methods that embody claims the repaired prose actually makes. Keep broad files sparse. - GROUNDING_DRIFT/body change: decide whether the claim changed from the supplied - old/new body. Repair only affected prose, then refresh that grounds_to entry - with the current node id and the exact current \`fingerprint\` from graph JSONL. + old/new body. Repair only affected prose. Preserve the existing grounds_to + fingerprint and bodyHash until the user explicitly accepts that entry in + sync's grounding review; completing the agent session does not accept it. - MOVED: sync may have already durably rebound a high-confidence move. Verify the grounds_to id and every inline mex:// anchor for that symbol use the new id, - and refresh the frontmatter fingerprint from the same new-node graph fact. + and retain its previous bodyHash. Identity repair does not establish that the + documented behavior still agrees with the implementation. - AMBIGUOUS: adjudicate the surfaced candidate with scope/query/impact. If it is the same behavior, update grounds_to and any matching inline anchor to that id; otherwise choose the correct graph node or remove the stale grounding/anchor. @@ -72,7 +74,8 @@ the repaired prose actually makes. Keep broad files sparse. grounds_to entries and inline anchors; if replacement behavior exists, ground and anchor the replacement using exact graph facts. -Frontmatter entries are \`{ node, fingerprint }\`. Inline navigation is exactly +Frontmatter entries are \`{ node, fingerprint, bodyHash? }\`. Never erase a prior +bodyHash to make drift disappear. Inline navigation is exactly \`mex://\`: fingerprints belong ONLY in grounds_to and never in an URI. Anchor only load-bearing symbol mentions, without changing their visible text. Before finishing, re-read each changed file and verify ids/fingerprints resolve, diff --git a/src/sync/index.ts b/src/sync/index.ts index 110b7b70..ae3ead9a 100644 --- a/src/sync/index.ts +++ b/src/sync/index.ts @@ -7,7 +7,8 @@ import { runDriftCheck } from "../drift/index.js"; import { isCliAvailable } from "../cli-tools.js"; import { buildSyncBrief, buildCombinedBrief } from "./brief-builder.js"; import { findScaffoldFiles } from "../drift/index.js"; -import { captureGroundingBaselines, loadGroundingRuntime, persistMovedGroundings } from "../graph/runtime.js"; +import { captureGroundingBaselines, groundingReviewNodeIds, loadGroundingRuntime, persistMovedGroundings, previewGroundingBaseline } from "../graph/runtime.js"; +import { writeGroundings } from "../markdown.js"; const INTERACTIVE_AI_TIMEOUT_MS = 15 * 60_000; @@ -98,11 +99,20 @@ async function pickSyncTool(configuredTools: AiTool[]): Promise { type SyncMode = "interactive" | "prompts"; +/** Internal seams for exercising a complete sync without launching an agent or terminal. */ +interface SyncDependencies { + ask?: (question: string) => Promise; + runAgent?: typeof runToolInteractive; + reviewGrounding?: boolean; +} + /** Run targeted sync: detect → brief → AI → verify → ask → loop */ export async function runSync( config: MexConfig, - opts: { dryRun?: boolean; includeWarnings?: boolean } + opts: { dryRun?: boolean; includeWarnings?: boolean }, + dependencies: SyncDependencies = {}, ): Promise { + const ask = dependencies.ask ?? askUser; let cycle = 0; let mode: SyncMode | null = null; let activeTool: AiTool | null = null; @@ -212,7 +222,7 @@ export async function runSync( console.log(" 3) Exit"); console.log(); - const choice = await askUser("Choice [1-3] (default: 1): "); + const choice = await ask("Choice [1-3] (default: 1): "); const picked = choice || "1"; switch (picked) { @@ -253,15 +263,20 @@ export async function runSync( console.log(chalk.bold(`\nSending all ${targets.length} file(s) to ${toolLabel} in one session...\n`)); const brief = await buildGroundingAwareBrief(targets, config); - const ok = runToolInteractive(activeTool!, brief, config.projectRoot); + const ok = (dependencies.runAgent ?? runToolInteractive)(activeTool!, brief, config.projectRoot); if (!ok) { console.log(chalk.red(` ✗ ${toolLabel} session failed`)); } else { try { - await captureGroundingBaselines(config, { updateFingerprints: true }); + // Completion authorizes verification and initial capture, never renewal + // of accepted knowledge. Literal-only edits can keep the same fingerprint. + await captureGroundingBaselines(config); + if (dependencies.reviewGrounding ?? (process.stdin.isTTY && process.stdout.isTTY)) { + await reviewGroundingBaselines(config, targets, ask); + } } catch { - // The following drift check reports graph degradation without crashing sync. + console.log(chalk.yellow("Grounding review could not finish. Existing baselines are preserved for entries that were not accepted.")); } } @@ -312,7 +327,7 @@ export async function runSync( ? remainingErrors + remainingWarnings : remainingErrors; - const answer = await askUser( + const answer = await ask( `\n${remaining} issue(s) remain. Run another cycle? [Y/n] ` ); @@ -323,6 +338,55 @@ export async function runSync( } } +/** Review one exact entry at a time; no graph lease is held while waiting for input. */ +export async function reviewGroundingBaselines( + config: MexConfig, + targets: readonly SyncTarget[], + ask: (question: string) => Promise = askUser, + write: (message: string) => void = console.log, +): Promise { + let inspected = 0; + for (const target of targets) { + if (!target.issues.some((issue) => issue.code.startsWith("GROUNDING_"))) continue; + const nodeIds = groundingReviewNodeIds(config, target.file); + if (nodeIds === null) { + write(`Grounding review for ${target.file} exceeds the inline review limit; its baseline is preserved.`); + continue; + } + for (const nodeId of nodeIds) { + if (++inspected > 64) { + write("The grounding review limit was reached; remaining baselines are preserved."); + return; + } + const runtime = await loadGroundingRuntime(config); + if (!runtime) return; + let review; + try { + review = previewGroundingBaseline(config, target.file, nodeId, runtime); + } finally { + runtime.close(); + } + if (!review) continue; + write(`\nGrounding review: ${target.file}\nNode: ${nodeId}`); + // Keep authored metadata/prose visible, but hide serialized grounding + // fingerprints. The acceptance still binds the original complete bytes. + write(`\nCurrent document (grounding metadata hidden):\n${writeGroundings(review.content, [])}`); + write(`\nPreviously accepted code:\n${review.oldBody ?? "Unavailable in this checkout; inspect the prior revision before accepting."}`); + write(`\nCurrent code:\n${review.newBody}`); + write("Accepting records that this claim was reviewed against the current code. Commit and push to share it."); + const answer = (await ask("Accept this grounding after reviewing the claim and current code? [y/N] ")).trim().toLowerCase(); + if (answer !== "y" && answer !== "yes") continue; + const result = await captureGroundingBaselines(config, { + acceptedGroundings: [review.acceptance], + warn: write, + }); + write(result.captured === 1 + ? "Accepted this grounding in the working tree." + : "Grounding was not accepted; its document or code changed. Review it again."); + } + } +} + async function buildGroundingAwareBrief(targets: SyncTarget[], config: MexConfig): Promise { try { const runtime = await loadGroundingRuntime(config); diff --git a/test/graph-grounding-body-hash.test.ts b/test/graph-grounding-body-hash.test.ts index f9b968ee..c94840b8 100644 --- a/test/graph-grounding-body-hash.test.ts +++ b/test/graph-grounding-body-hash.test.ts @@ -12,16 +12,19 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { afterEach, describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import type { MexConfig } from "../src/types.js"; import { runDriftCheckWithGraphStatus } from "../src/drift/index.js"; import { createGraphEngine } from "../src/graph/engine-impl.js"; -import { loadGroundingRuntime, refreshGroundingBaselines } from "../src/graph/runtime.js"; +import { captureGroundingBaselines, loadGroundingRuntime, persistMovedGroundings, previewGroundingBaseline, refreshGroundingBaselines } from "../src/graph/runtime.js"; +import { runSync, reviewGroundingBaselines } from "../src/sync/index.js"; import { extractGroundings, writeGroundings } from "../src/markdown.js"; import { serializeFingerprint } from "../src/graph/fingerprint.js"; const roots: string[] = []; +vi.mock("../src/cli-tools.js", () => ({ isCliAvailable: () => true })); + /** The body an agent grounds to, and the one-constant edit that drifts it. */ const ORIGINAL = `export function calculateOrderTotal(items: number[]): number { const subtotal = items.reduce((sum, item) => sum + item, 0); @@ -79,20 +82,11 @@ async function authorGrounding( } } -/** - * Capture in the posture `mex ground` and setup use. - * - * `captureGroundingBaselines` normalizes a missing `updateFingerprints` to - * `false` before it reaches `refreshGroundingBaselines`, so passing it - * explicitly is what makes these tests exercise the real command path rather - * than the looser default a direct caller gets. It matters: `false` is the - * read-only posture that must never overwrite a hash that has drifted, while - * `mex sync` passes `true` after an agent pass and re-baselines deliberately. - */ +/** Every default caller initializes missing baselines but preserves accepted ones. */ async function captureBaselines(config: MexConfig, scaffold: string): Promise { const runtime = await loadGroundingRuntime(config); try { - refreshGroundingBaselines(config, [scaffold], runtime!, { updateFingerprints: false }); + refreshGroundingBaselines(config, [scaffold], runtime!); } finally { runtime!.close(); } @@ -113,6 +107,7 @@ async function groundingIssueCodes(config: MexConfig): Promise { } afterEach(() => { + vi.restoreAllMocks(); for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); @@ -224,3 +219,228 @@ describe("the grounding body hash is committed to Markdown", () => { expect(await groundingIssueCodes(config)).toEqual(["GROUNDING_DRIFT"]); }, 60_000); }); + +describe("grounding renewal requires an exact reviewed entry", () => { + async function ready() { + const target = fixture(); + await buildGraph(target.root); + const nodeId = await authorGrounding(target.config, target.scaffold, "calculateOrderTotal"); + await captureBaselines(target.config, target.scaffold); + const runtime = await loadGroundingRuntime(target.config); + const baseline = runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)!; + runtime!.close(); + return { ...target, nodeId, baseline }; + } + + it("a successful no-op agent session preserves drift, canonical bytes, and cached old code", async () => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + const before = readFileSync(scaffold, "utf-8"); + writeFileSync(source, EDITED); + const runAgent = vi.fn(() => true); + const answers = ["1", "n"]; + vi.spyOn(console, "log").mockImplementation(() => {}); + await runSync({ ...config, aiTools: ["claude"] }, {}, { + runAgent, + ask: async () => answers.shift() ?? "n", + reviewGrounding: false, + }); + expect(runAgent).toHaveBeenCalledOnce(); + expect(readFileSync(scaffold, "utf-8")).toBe(before); + const runtime = await loadGroundingRuntime(config); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + runtime!.close(); + expect(await groundingIssueCodes(config)).toEqual(["GROUNDING_DRIFT"]); + }, 60_000); + + it("backfills legacy Markdown from its old cache after a literal-only edit and survives rebuild", async () => { + const { config, root, source, scaffold, nodeId, baseline } = await ready(); + const stripped = extractGroundings(readFileSync(scaffold, "utf-8")) + .map(({ node, fingerprint }) => ({ node, fingerprint })); + writeFileSync(scaffold, writeGroundings(readFileSync(scaffold, "utf-8"), stripped)); + writeFileSync(source, EDITED); + const result = await captureGroundingBaselines(config); + expect(result).toEqual({ captured: 0, skipped: 1 }); + expect(extractGroundings(readFileSync(scaffold, "utf-8"))[0]!.bodyHash).toBe(baseline.bodyHash); + const runtime = await loadGroundingRuntime(config); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + runtime!.close(); + await rebuildGraphFromScratch(root); + expect(await groundingIssueCodes(config)).toEqual(["GROUNDING_DRIFT"]); + }, 60_000); + + it("accepts only the selected document entry and leaves another grounding drifted across rebuild", async () => { + const { config, root, source, scaffold, nodeId } = await ready(); + const other = join(root, ".mex", "context", "other.md"); + writeFileSync(other, readFileSync(scaffold)); + await captureGroundingBaselines(config); + const otherBefore = readFileSync(other, "utf-8"); + writeFileSync(source, EDITED); + const runtime = await loadGroundingRuntime(config); + const review = previewGroundingBaseline(config, ".mex/context/architecture.md", nodeId, runtime!)!; + const otherBaseline = runtime!.fingerprints.getGroundedSource(".mex/context/other.md", nodeId); + runtime!.close(); + expect(review.oldBody).toContain("subtotal * 0.18"); + expect(review.newBody).toContain("subtotal * 0.21"); + expect(await captureGroundingBaselines(config, { acceptedGroundings: [review.acceptance] })) + .toEqual({ captured: 1, skipped: 0 }); + expect(readFileSync(other, "utf-8")).toBe(otherBefore); + const after = await loadGroundingRuntime(config); + expect(after!.fingerprints.getGroundedSource(".mex/context/other.md", nodeId)).toEqual(otherBaseline); + after!.close(); + expect(extractGroundings(readFileSync(scaffold, "utf-8"))[0]!.bodyHash).toBe(review.acceptance.bodyHash); + await rebuildGraphFromScratch(root); + const report = await runDriftCheckWithGraphStatus(config); + expect(report.issues.filter((entry) => entry.code === "GROUNDING_DRIFT")) + .toMatchObject([{ file: ".mex/context/other.md" }]); + }, 60_000); + + it.each(["document", "source"] as const)("rejects acceptance when the %s changes after preview", async (changed) => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED); + const runtime = await loadGroundingRuntime(config); + const acceptance = previewGroundingBaseline(config, ".mex/context/architecture.md", nodeId, runtime!)!.acceptance; + runtime!.close(); + if (changed === "document") writeFileSync(scaffold, readFileSync(scaffold, "utf-8") + "\nConcurrent clarification.\n"); + else writeFileSync(source, EDITED.replace("subtotal * 0.21", "subtotal * 0.25")); + const before = readFileSync(scaffold, "utf-8"); + expect(await captureGroundingBaselines(config, { acceptedGroundings: [acceptance] })) + .toEqual({ captured: 0, skipped: 1 }); + expect(readFileSync(scaffold, "utf-8")).toBe(before); + const after = await loadGroundingRuntime(config); + expect(after!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + after!.close(); + }, 60_000); + + it("preserves a concurrent document edit and the old cache during acceptance preparation", async () => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED); + const runtime = await loadGroundingRuntime(config); + try { + const acceptance = previewGroundingBaseline(config, ".mex/context/architecture.md", nodeId, runtime!)!.acceptance; + const concurrent = readFileSync(scaffold, "utf-8") + "\nConcurrent clarification.\n"; + const getNode = runtime!.graph.getNode.bind(runtime!.graph); + let reads = 0; + vi.spyOn(runtime!.graph, "getNode").mockImplementation((id) => { + if (++reads === 2) writeFileSync(scaffold, concurrent); + return getNode(id); + }); + expect(refreshGroundingBaselines(config, [scaffold], runtime!, { acceptedGroundings: [acceptance] })) + .toEqual({ captured: 0, skipped: 1 }); + expect(readFileSync(scaffold, "utf-8")).toBe(concurrent); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + } finally { + runtime!.close(); + } + }, 60_000); + + it("keeps MOVED content drift and historical cache after rebinding a legacy grounding", async () => { + const { config, root, source, scaffold, nodeId, baseline } = await ready(); + const stripped = extractGroundings(readFileSync(scaffold, "utf-8")) + .map(({ node, fingerprint }) => ({ node, fingerprint })); + writeFileSync(scaffold, writeGroundings(readFileSync(scaffold, "utf-8"), stripped)); + writeFileSync(source, EDITED.replace("calculateOrderTotal", "computeOrderTotal")); + const runtime = await loadGroundingRuntime(config); + expect(persistMovedGroundings(config, [scaffold], runtime!)).toBe(1); + const moved = extractGroundings(readFileSync(scaffold, "utf-8"))[0]!; + expect(moved.node).not.toBe(nodeId); + expect(moved.bodyHash).toBe(baseline.bodyHash); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", moved.node)) + .toEqual({ ...baseline, nodeId: moved.node }); + runtime!.close(); + await rebuildGraphFromScratch(root); + expect(await groundingIssueCodes(config)).toEqual(["GROUNDING_DRIFT"]); + }, 60_000); + + it("preserves canonical destination evidence when a MOVED pointer would collide", async () => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED.replace("calculateOrderTotal", "computeOrderTotal")); + const runtime = await loadGroundingRuntime(config); + try { + const current = runtime!.graph.searchNodes("computeOrderTotal").find((entry) => entry.kind === "function")!; + const currentFingerprint = serializeFingerprint(runtime!.reconciler.getFingerprint(current.id)!); + const original = extractGroundings(readFileSync(scaffold, "utf-8"))[0]!; + const destination = { ...baseline, nodeId: current.id, source: EDITED.replace("calculateOrderTotal", "computeOrderTotal").trimEnd(), bodyHash: current.bodyHash!, fingerprint: currentFingerprint }; + runtime!.fingerprints.saveGroundedSource(destination); + writeFileSync(scaffold, writeGroundings(readFileSync(scaffold, "utf-8"), [original, { + node: current.id, fingerprint: currentFingerprint, bodyHash: current.bodyHash, + }]) + `\n[Old name](mex://${nodeId})\n`); + expect(persistMovedGroundings(config, [scaffold], runtime!)).toBe(1); + expect(extractGroundings(readFileSync(scaffold, "utf-8")).map((entry) => entry.node)).toEqual([nodeId, current.id]); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", current.id)).toEqual(destination); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + } finally { + runtime!.close(); + } + }, 60_000); + + it("retains the old MOVED cache when the document changes before pointer publication", async () => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED.replace("calculateOrderTotal", "computeOrderTotal")); + const runtime = await loadGroundingRuntime(config); + try { + const concurrent = readFileSync(scaffold, "utf-8") + "\nConcurrent clarification.\n"; + const getNode = runtime!.graph.getNode.bind(runtime!.graph); + vi.spyOn(runtime!.graph, "getNode").mockImplementationOnce((id) => { + writeFileSync(scaffold, concurrent); + return getNode(id); + }); + expect(() => persistMovedGroundings(config, [scaffold], runtime!)).toThrow("changed before publication"); + expect(readFileSync(scaffold, "utf-8")).toBe(concurrent); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + } finally { + runtime!.close(); + } + }, 60_000); + + it.each(["oversized", "invalid-utf8"] as const)("rejects an %s accepted document without changing the old cache", async (kind) => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED); + const runtime = await loadGroundingRuntime(config); + try { + const acceptance = previewGroundingBaseline(config, ".mex/context/architecture.md", nodeId, runtime!)!.acceptance; + const changed = Buffer.concat([readFileSync(scaffold), kind === "oversized" ? Buffer.alloc(64 * 1024, 32) : Buffer.from([0xff])]); + writeFileSync(scaffold, changed); + expect(() => refreshGroundingBaselines(config, [scaffold], runtime!, { acceptedGroundings: [acceptance] })).toThrow(); + expect(readFileSync(scaffold)).toEqual(changed); + expect(runtime!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + } finally { + runtime!.close(); + } + }, 60_000); + + it("reviews default-no and then accepts one entry without holding a graph lease across input", async () => { + const { config, source, scaffold, nodeId, baseline } = await ready(); + writeFileSync(source, EDITED); + const targets = [{ file: ".mex/context/architecture.md", gitDiff: null, issues: [{ + code: "GROUNDING_DRIFT" as const, severity: "warning" as const, file: ".mex/context/architecture.md", line: null, message: `Grounded node body changed: ${nodeId}`, + }] }]; + const before = readFileSync(scaffold, "utf-8"); + await reviewGroundingBaselines(config, targets, async () => "", () => {}); + expect(readFileSync(scaffold, "utf-8")).toBe(before); + const messages: string[] = []; + await reviewGroundingBaselines(config, targets, async () => { + const whilePrompting = await loadGroundingRuntime(config); + expect(whilePrompting!.fingerprints.getGroundedSource(".mex/context/architecture.md", nodeId)).toEqual(baseline); + whilePrompting!.close(); + return "yes"; + }, (message) => messages.push(message)); + expect(messages.join("\n")).toContain("Previously accepted code:"); + expect(messages.join("\n")).toContain("grounding metadata hidden"); + expect(messages.join("\n")).not.toContain(baseline.fingerprint); + expect(messages.join("\n")).toContain("name: architecture"); + expect(messages.join("\n")).toContain("subtotal * 0.18"); + expect(messages.join("\n")).toContain("subtotal * 0.21"); + expect(await groundingIssueCodes(config)).toEqual([]); + }, 60_000); + + it("does not label an unrelated cached body as the canonically accepted code", async () => { + const { config, source, scaffold, nodeId } = await ready(); + const groundings = extractGroundings(readFileSync(scaffold, "utf-8")); + groundings[0]!.bodyHash = "a".repeat(64); + writeFileSync(scaffold, writeGroundings(readFileSync(scaffold, "utf-8"), groundings)); + writeFileSync(source, EDITED); + const runtime = await loadGroundingRuntime(config); + expect(previewGroundingBaseline(config, ".mex/context/architecture.md", nodeId, runtime!)!.oldBody).toBeNull(); + runtime!.close(); + }, 60_000); +}); diff --git a/test/graph-grounding.test.ts b/test/graph-grounding.test.ts index 30a7a3a8..0d6bb5f3 100644 --- a/test/graph-grounding.test.ts +++ b/test/graph-grounding.test.ts @@ -174,6 +174,16 @@ describe("grounding checker", () => { expect(grounding.node).toBe("new-id"); }); + it("reports changed accepted content after MOVED resolution before pointer persistence", () => { + const grounding = { node: "missing", fingerprint: serializeFingerprint(fingerprint(64)), bodyHash: "accepted-hash" }; + const checker = createGroundingChecker(graph([node("new-id", "changed-hash")]), { + reconcile: () => ({ kind: "MOVED", nodeId: "new-id" }), + }); + expect(checker({ grounds_to: [grounding] }, "/repo/.mex/context.md", "context.md", "/repo", "/repo/.mex")) + .toMatchObject([{ code: "GROUNDING_DRIFT", severity: "warning" }]); + expect(grounding.bodyHash).toBe("accepted-hash"); + }); + it("handles inline anchor hit, MOVED, GONE, and AMBIGUOUS as warning-only navigation drift", () => { const root = mkdtempSync(join(tmpdir(), "mex-anchor-check-")); const file = join(root, "context.md"); diff --git a/test/graph-integration.test.ts b/test/graph-integration.test.ts index f250a8d8..d175d96c 100644 --- a/test/graph-integration.test.ts +++ b/test/graph-integration.test.ts @@ -20,6 +20,7 @@ import { loadGroundingRuntime, loadReadOnlyGroundingRuntime, persistMovedGroundings, + previewGroundingBaseline, refreshGroundingBaselines, type GroundingRuntime, } from "../src/graph/runtime.js"; @@ -346,10 +347,11 @@ describe("code-graph grounding integration", () => { issues: report.issues.filter((issue) => issue.code === "GROUNDING_DRIFT"), }], root, { config, runtime: runtime! }); expect(bodyRepairBrief).toContain("GROUNDING REPAIR"); - expect(bodyRepairBrief).toContain("refresh that grounds_to entry"); + expect(bodyRepairBrief).toContain("user explicitly accepts that entry"); expect(bodyRepairBrief).toContain('mex graph scope ""'); expect(bodyRepairBrief).toContain("fingerprints belong ONLY in grounds_to"); - refreshGroundingBaselines(config, [scaffold], runtime!); + const acceptance = previewGroundingBaseline(config, ".mex/context/architecture.md", node.id, runtime!)!.acceptance; + refreshGroundingBaselines(config, [scaffold], runtime!, { acceptedGroundings: [acceptance] }); runtime!.close(); const refreshedContent = readFileSync(scaffold, "utf-8"); expect(extractGroundings(refreshedContent)[0].fingerprint).not.toBe(initialFingerprint); @@ -385,17 +387,21 @@ describe("code-graph grounding integration", () => { expect(anchorAmbiguousBrief).toContain("AMBIGUOUS: adjudicate the surfaced candidate"); expect(anchorAmbiguousBrief).toContain("any matching inline anchor"); const moved = persistMovedGroundings(config, [scaffold], runtime!); + const oldHash = extractGroundings(refreshedContent)[0].bodyHash; runtime!.close(); expect(moved).toBe(2); const persisted = extractGroundings(readFileSync(scaffold, "utf-8")); expect(persisted[0].node).not.toBe(node.id); expect(persisted[0].node).toContain("function:"); + expect(persisted[0].bodyHash).toBe(oldHash); const persistedContent = readFileSync(scaffold, "utf-8"); expect(persistedContent).not.toContain(`mex://${node.id}`); expect(persistedContent).toContain(`mex://${persisted[0].node}`); report = await runDriftCheckWithGraphStatus(config, { graphWarning: warning }); expect(report.graphStatus?.status).toBe("fresh"); - expect(report.issues.filter((issue) => issue.code.startsWith("GROUNDING_"))).toHaveLength(0); + expect(report.issues.filter((issue) => issue.code.startsWith("GROUNDING_"))).toMatchObject([ + { code: "GROUNDING_DRIFT" }, + ]); }, 20_000); it("keeps legacy checks running when the graph engine fails to load", async () => { diff --git a/test/setup-grounding-e2e.test.ts b/test/setup-grounding-e2e.test.ts index 9bc668e4..02e66bde 100644 --- a/test/setup-grounding-e2e.test.ts +++ b/test/setup-grounding-e2e.test.ts @@ -13,7 +13,7 @@ import { deserializeFingerprint } from "../src/graph/fingerprint.js"; import { extractGroundings, findMexAnchors, writeGroundings } from "../src/markdown.js"; import { checkBrokenLinks } from "../src/drift/checkers/broken-link.js"; import { runDriftCheckWithGraphStatus } from "../src/drift/index.js"; -import { captureGroundingBaselines, loadGroundingRuntime } from "../src/graph/runtime.js"; +import { captureGroundingBaselines, loadGroundingRuntime, previewGroundingBaseline } from "../src/graph/runtime.js"; import { finalizeSetupWiki } from "../src/setup/wiki-finalize.js"; const roots: string[] = []; @@ -141,9 +141,13 @@ export function calculateCheckoutTotal(items: number[], member: boolean): number file: ".mex/patterns/calculate-checkout.md", })); - // Same shared post-authoring routine used by sync: refresh, then check clean. - expect(await captureGroundingBaselines(config, { updateFingerprints: true })) - .toEqual({ captured: 2, skipped: 0 }); + // Review this behavioral claim explicitly. Its navigation-only sibling is + // not a behavioral assertion and keeps its historical cache unchanged. + const reviewRuntime = await loadGroundingRuntime(config); + const acceptance = previewGroundingBaseline(config, ".mex/patterns/calculate-checkout.md", groundings[0].node, reviewRuntime!)!.acceptance; + reviewRuntime!.close(); + expect(await captureGroundingBaselines(config, { acceptedGroundings: [acceptance] })) + .toEqual({ captured: 1, skipped: 0 }); const clean = await runDriftCheckWithGraphStatus(config, { graphWarning: (message) => warnings.push(message) }); expect(clean.graphStatus?.status).toBe("fresh"); expect(clean.issues.filter((issue) => issue.code.startsWith("GROUNDING_"))).toEqual([]); From 519e1847ab1cfd69b308fa633833a1bf3fc16324 Mon Sep 17 00:00:00 2001 From: theDakshJaitly Date: Tue, 8 Sep 2026 01:19:54 +0530 Subject: [PATCH 02/19] feat(hub): add Context graph and simplify team navigation --- .mex/ROUTER.md | 23 +- .mex/patterns/secure-local-project-hub.md | 11 +- docs/design/0.8.1-release-plan.md | 221 ++++++++++++++++++ packages/hub-contracts/src/index.test.ts | 24 ++ packages/hub-contracts/src/index.ts | 44 ++++ packages/hub-web/src/api/client.ts | 14 ++ packages/hub-web/src/api/types.ts | 2 + packages/hub-web/src/app/App.test.tsx | 49 ++-- packages/hub-web/src/app/App.tsx | 2 +- packages/hub-web/src/app/HubSidebar.test.tsx | 27 +-- packages/hub-web/src/app/HubSidebar.tsx | 9 - .../src/app/JobLifecycleObserver.test.tsx | 67 +++++- .../hub-web/src/app/JobLifecycleObserver.tsx | 6 + .../hub-web/src/app/context-page.test.tsx | 207 ++++++++++++++++ .../hub-web/src/app/knowledge-pages.test.tsx | 33 ++- packages/hub-web/src/app/navigation.ts | 65 +----- packages/hub-web/src/app/page-states.test.tsx | 21 +- .../src/components/ContextGraphCanvas.tsx | 111 +++++++++ packages/hub-web/src/dev/fixture-api.ts | 16 ++ .../hub-web/src/lib/context-graph.test.ts | 139 +++++++++++ packages/hub-web/src/lib/context-graph.ts | 87 +++++++ packages/hub-web/src/pages/ContextPage.tsx | 124 ++++++++++ packages/hub-web/src/pages/HomeOverview.tsx | 98 +++----- packages/hub-web/src/pages/KnowledgePage.tsx | 11 +- .../src/styles/context-graph.module.css | 28 +++ .../hub-web/src/styles/context.module.css | 30 +++ packages/hub-web/src/styles/global.css | 4 + packages/hub-web/src/styles/home.module.css | 7 + scripts/release-benchmark/assets.mjs | 2 + scripts/release-benchmark/browser.mjs | 8 +- scripts/release-benchmark/hub.mjs | 10 +- .../release-benchmark.test.js | 76 +++++- scripts/release-benchmark/routes.mjs | 2 +- .../__tests__/application-adapter.test.ts | 94 +++++++- src/graph/application-adapter.ts | 20 ++ src/hub/__tests__/services.test.ts | 144 ++++++++++++ src/hub/app.ts | 19 ++ src/hub/services.ts | 67 ++++++ src/wiki/__tests__/context-graph.test.ts | 151 ++++++++++++ src/wiki/application-adapter.ts | 115 +++++++++ .../__screenshots__/darwin/hub-home.png | Bin 229009 -> 235427 bytes .../darwin/hub-sidebar-populated.png | Bin 28855 -> 21110 bytes test/hub-e2e/context-graph.spec.ts | 46 ++++ test/hub-e2e/hub.spec.ts | 91 +++----- test/hub-wiki-integration.test.ts | 30 +++ 45 files changed, 2055 insertions(+), 300 deletions(-) create mode 100644 docs/design/0.8.1-release-plan.md create mode 100644 packages/hub-web/src/app/context-page.test.tsx create mode 100644 packages/hub-web/src/components/ContextGraphCanvas.tsx create mode 100644 packages/hub-web/src/lib/context-graph.test.ts create mode 100644 packages/hub-web/src/lib/context-graph.ts create mode 100644 packages/hub-web/src/pages/ContextPage.tsx create mode 100644 packages/hub-web/src/styles/context-graph.module.css create mode 100644 packages/hub-web/src/styles/context.module.css create mode 100644 src/wiki/__tests__/context-graph.test.ts create mode 100644 test/hub-e2e/context-graph.spec.ts diff --git a/.mex/ROUTER.md b/.mex/ROUTER.md index 6bd5d807..cb5e9c7e 100644 --- a/.mex/ROUTER.md +++ b/.mex/ROUTER.md @@ -16,7 +16,7 @@ edges: condition: when starting a task — check the pattern index for a matching pattern file - target: patterns/release-readme-visuals.md condition: when refreshing the release README, badges, community links, or architecture illustrations -last_updated: 2026-09-06 +last_updated: 2026-09-08 --- # Session Bootstrap @@ -65,12 +65,29 @@ Then read this file fully before doing anything else in this session. - Versioned graph snapshot provenance and read-only freshness inspection gate grounding in check, doctor, and dashboard flows without implicit graph sync. - Grounding carries its change signal in Markdown: `grounds_to[].bodyHash` is - optional and additive, written by the capture and MOVED-repair passes from the - graph's own hash, and backfilled for existing scaffolds on the next capture. + optional and additive, written during initial capture or an explicitly + accepted per-entry sync review from the graph's own hash. Legacy backfill + preserves an existing cached baseline, and MOVED repairs carry earlier change + evidence forward rather than accepting the new body. The `_mex_grounded_source` row remains as a cache of that canonical value. The drift checker prefers the committed hash, falls back to the cache for a grounding authored before the field, and resolves the `grounds_to` key path so migrated scaffolds under `mex.grounds_to` are checked rather than skipped. +- The first 0.8.1 release phase is implemented on `codex/0.8.1`: successful + agent exit no longer authorizes baseline renewal. Interactive sync offers + bounded default-no review of individual groundings, releases the graph lease + before asking, and revalidates document bytes and graph facts before applying. + The remaining release phases, including logging cadence/retrieval, Windows + hardening, and separate final telemetry work, are tracked in + `docs/design/0.8.1-release-plan.md`. +- Phase 2 adds a graph-first Context Hub at `/knowledge`, with every usual + Wiki entity (including unlinked sections), recorded relationships, and direct + code groundings expanding on selection. The list and full-record routes remain + readable. Bounded private graph/code projections never maintain indexes; + completed Graph/Wiki jobs invalidate the Context caches. Home and primary + navigation now emphasize Context, Code, Relays, and Activity while legacy + workflow routes remain readable. Local verification is recorded in the + same release plan; this is local implementation, not a published release. - Explicit graph status, refresh, and isolated rebuild/recovery commands preserve the last trustworthy index behind one cross-process maintenance lease. - Targeted graph get/query/impact consumers use one provenance-bound immutable diff --git a/.mex/patterns/secure-local-project-hub.md b/.mex/patterns/secure-local-project-hub.md index 84d0d417..7accbda3 100644 --- a/.mex/patterns/secure-local-project-hub.md +++ b/.mex/patterns/secure-local-project-hub.md @@ -11,12 +11,12 @@ edges: condition: "when persisting a Hub job or migrating team.db" - target: "context/architecture.md" condition: "when wiring a real Graph or Wiki adapter" -last_updated: 2026-09-06 +last_updated: 2026-09-08 mex: id: mx_01M1M0CJQ2BSV71G1C7TXZD9RH type: pattern status: promoted - revision: 3 + revision: 4 title: secure-local-project-hub grounds_to: - node: function:188820af31f0d74c6518f6926f559877 @@ -96,6 +96,13 @@ preview/apply services. subject/message previews before response validation. Schema-v2 Activity workflow/custom origin and optional labels use their closed projections. +- New read surfaces need successful-job cache invalidation as well as their + initial query. Context's graph, selected record, and compact code queries all + refresh after Graph/Wiki maintenance; the Wiki revision can stay unchanged + while code health or signatures change. Each code projection carries its own + Graph observation, so do not claim aggregate health across separately observed + panels is one shared Graph snapshot. + ## Verify - [ ] Host, Origin, CSRF, expiry, traversal, body, response, and SSE bounds pass diff --git a/docs/design/0.8.1-release-plan.md b/docs/design/0.8.1-release-plan.md new file mode 100644 index 00000000..aea660e0 --- /dev/null +++ b/docs/design/0.8.1-release-plan.md @@ -0,0 +1,221 @@ +# MEX 0.8.1 release plan + +Status: Phases 1 and 2 implemented and locally verified. +Implementation of later phases has not started. +Branch: `codex/0.8.1`, starting from `4942489`. + +## Release intent + +Make the existing product easier to understand and dependable in an ordinary +small team: visual repository context, practical Relays, and trustworthy +grounding. Reuse the current engines and contracts. Keep telemetry as a separate +final change, and isolate Windows changes so their effects can be reviewed. + +Implementation, local verification, and committing the completed Phases 1–2 +are authorized. Push, release publication, and telemetry delivery remain outside +this checkpoint. + +## Phases + +| Phase | Scope | Done when | Status | +| --- | --- | --- | --- | +| 1. Grounding safety | Remove agent-exit-driven baseline renewal; preserve old evidence; make acceptance explicit and scoped; retain initial capture; keep moved-symbol repair from accepting changed behavior. | No-op agents cannot clear drift; explicit acceptance affects only reviewed entries; setup, legacy grounding, moved symbols, and index rebuild remain covered. | Locally verified | +| 2. Context-focused Hub | Show all knowledge entities in a graph-first Context view, organized by type, with direct code groundings expanding on selection and details in a sidebar. Retain search/filters and a list alternative. Simplify navigation and retire Specs/Workstreams/Spec-only Inbox from the primary experience. | The usual 25–35 entities are visible together, including unlinked sections; recorded relationships and code groundings are useful to explore; old artifacts and links remain readable; route and resource budgets hold. | Locally verified | +| 3. Practical Relays | Open-to-team audience including future active Members; drafts without recipients; shorter agent/CLI saving; persistent sharing and claim-eligibility information; inactive-member recovery. | An engineer can save context now and an eligible teammate can take it later; local publication is never presented as verified delivery. | Not started | +| 4. Focused corrections and knowledge reuse | Unknown-file migration classification, contribution/evidence provenance, confirmed fresh-install bugs, configurable agent logging and relevant log retrieval, docs/translations. | Identified defects are fixed; logging policy is understandable; prior notes can inform work without treating every note as accepted knowledge. | Not started | +| 5. Windows hardening | Two independently reviewable changes: narrow CRLF normalization, then preserve full-width inode identity in affected paths. | Content/revision, preview/recovery, replacement, and lock checks pass, including real Windows coverage. | Not started | +| 6. Telemetry | Separate final change: namespaced CLI commands and outcomes; server-side allowlisted Hub events excluding IDs, paths, content, search text, and personal data; honor opt-outs. | Payloads, outcomes, opt-outs, and documentation have dedicated verification. | Not started | + +## Phase 1 boundary + +The safety change is about authorization to replace a baseline. It does not +change code extraction, fingerprint matching, graph schemas, or the public +package API. The expected production changes are in sync, its repair brief, +and the shared grounding runtime. Setup and grounding migration are regression +surfaces because they use that runtime. + +- A successful agent process triggers verification; it does not accept changed + knowledge. +- Existing Markdown baselines and cached old-source evidence survive unless a + specific replacement has been explicitly authorized. +- Initial capture remains available. Legacy backfill uses existing evidence + where it exists instead of silently resetting it to current code. +- Acceptance is scoped to selected groundings and concrete graph facts, using + a small explicit operation rather than a new review workflow. +- Pointer repair preserves earlier change evidence. Smarter automatic + classification of harmless renames is outside this release. + +Initial effort estimate: roughly 2–4 focused engineering days including +regressions; legacy and moved-symbol behavior are the main uncertainties. + +### Phase 1 result + +Interactive sync now presents a default-no review for one grounding at a time, +showing the current document and previous/current code. Serialized grounding +metadata is omitted from the display; approval still binds the complete +document bytes. No graph lease remains held while waiting for the user. A +non-interactive run preserves baselines instead of inferring acceptance. + +Accepted replacements revalidate the document and exact graph facts. Writes +are bounded and reject stale inputs or invalid UTF-8; the canonical document +is published before its cache changes. MOVED repair carries prior evidence +forward, including on failure or an existing destination grounding. + +Local verification: + +- Seven focused files passed: 67 tests covering sync, grounding, setup, + migration, moved symbols, cache preservation, and stale/oversized inputs. +- The two sync/no-op review regressions passed again after the last bounded + reader adjustment. +- An isolated test against starting commit `4942489` reproduced the defect: + code changed from 18% to 21%, capture replaced the baseline, and the document + still said 18%. The identical test passed with the new source. +- `npm run typecheck` passed for the root and both Hub workspaces. +- `npm run build:node` passed, including contract and package declarations. +- `git diff --check` passed. The package-root exports and graph schemas are + unchanged. + +This is Phase 1 verification, not approval to publish 0.8.1. The remaining +phases and integrated release/Windows checks are still pending. + +## Phase 2 graph direction + +- Show every knowledge entity in the normal 25–35 entity repository at once, + including document and section entities without explicit relationships. + Do not collapse these into document groups or stop at the first browse page. +- Use small circular nodes with readable labels beside or below them, thin + curved links, and a spacious organic layout. Adapt the reference to the + existing Hub charcoal background and orange accents. +- Softly group nodes by their recorded entity type within that organic layout + and give types consistent, restrained colors with a textual legend. Type + coloring and grounding health must remain distinguishable. +- Draw existing recorded relationships; expose their type and optional note on + selection. Spatial proximity is grouping, not an authored relationship. +- Selecting a Wiki entity highlights its knowledge connections, opens its + details in the sidebar, and reveals its directly grounded code symbols as + nearby nodes with a distinct code treatment and grounding-edge style. +- Preserve the knowledge layout while code connections expand. Use a short + expansion transition and honor reduced motion. Selecting another Wiki entity + replaces the expanded code nodes; clearing selection collapses them. Selecting + a code node keeps the originating Wiki context open and shows symbol details. +- Use recorded symbol identities, names, and source locations. Preserve missing + or unresolved grounding states; an entity without groundings gets an honest + empty state. Do not expand the full call graph automatically. +- Reuse the existing Wiki and Code engines and freshness checks. Add only the + bounded read projections needed by this view. Keep all ordinary reads free of + maintenance and show when a larger corpus exceeds an established budget. + +Read-only design audit of this repository: 30 Wiki entities, 36 directed +relationships (all `related_to`), and 12 code groundings across seven patterns. +Thirteen document entities are connected; 17 section entities have no explicit +relationships. Topics, sources, and provenance are currently unpopulated. The +first view must be useful with this data, without invented links or attribution. +Grounding freshness was not assessed for this design audit. + +### Phase 2 result + +`/knowledge` now opens the Context graph. All entities in the usual repository +fit in one bounded overview, including disconnected sections. Type colors, +recorded links, local highlighting, pan/zoom/fit, and a detail sidebar are +implemented. Selecting a Wiki node reveals its directly resolved code symbols; +selecting code retains the parent knowledge. Existing list filters, full records, +and legacy workflow routes remain available. + +Two private read-only projections provide a single Wiki overview and compact +per-entity code details. Limits are 100 entities, 500 relationships, 50 direct +code references, and the existing 1 MiB response bound. Partial coverage, +unavailable indexes, missing symbols, and revision mismatches remain explicit. +Reads never refresh indexes or fetch source bodies merely to expand code. +Successful Graph/Wiki jobs invalidate every Context query, including when the +Wiki revision itself stays unchanged. + +Home and primary navigation now emphasize Context, Code, Relays, and Activity. +Specs, Workstreams, and Spec-only Inbox have left the primary navigation; their +existing artifacts and direct routes remain readable. + +Local verification: + +- Public boundary: `src/index.ts`, package metadata, and dependencies unchanged. +- Read safety and bounds: 72 focused backend/contract tests passed, including + authenticated real Hub reads, immutable snapshots, stale rejection, compact + symbol allowlisting, truncation, and protected file bytes/mtimes. +- Hub tests: 410/410 passed with one worker. An initial concurrent run had three + loading timeouts in existing Inbox/Member tests; both affected suites then + passed independently before the entire serial run passed. +- TypeScript: final `npm run typecheck` passed for root and both Hub workspaces. +- Packaging: full `npm run build` passed; the final frontend changes passed + `build:hub` again. No Graph evaluator/protocol behavior changed in Phase 2. +- Browser: final graph tests passed at 1024 and 1440 pixels, plus production + bootstrap/origin/idle/fixture-exclusion smoke. Earlier focused Home, sidebar, + list, route, keyboard, and accessibility checks passed. Two changed macOS + Home/sidebar screenshots were regenerated and visually reviewed. +- Visual density: the actual 30-record design sample, with code expansion, + produced no overlapping node boxes, browser errors, or page overflow at + 1024 and 1440 pixels. This sample does not assert current grounding freshness. +- Assets: all existing deterministic budgets pass unchanged. Context adds + 25,616 JavaScript bytes and 6,841 CSS bytes; initial assets are 462,634 + JavaScript bytes and 70,574 CSS bytes. Context and the deferred list/detail + remain outside the shell and Home closures. +- Benchmark wiring: 39/39 focused tests passed, including the default graph + read path, populated browser readiness, and separate graph/list asset closures. +- Worktree: `git diff --check` passed; no generated indexes, local state, + dependencies, or built artifacts are included in the local commit checkpoint. + +Pinned Ubuntu runtime/heap/latency gates, packed fresh-install coverage, and +Windows checks remain release gates. The Knowledge read benchmark now targets +`/wiki/graph` and browser readiness requires the populated graph; existing +runtime budgets remain unchanged and are not claimed to pass from local timing. +Phases 3–6 remain unstarted. + +## Logging addition + +`mex log` currently appends notes/decisions/risks/todos to +`.mex/events/decisions.jsonl`. These can be read through Timeline and are +projected into Hub Activity as Project notes. The JSONL is not ordinary Wiki +knowledge, and current agent instructions do not reliably retrieve it. + +Keep the change small: + +- Provide an explicit policy for agent logging: `significant` (quiet default), + `checkpoints` (batch at task/session boundaries), and `manual`. Explain that the + policy guides agents; explicit user-requested records must still be saved. +- Expose the logging preference in Hub Settings, backed by the same policy used + by agent instructions and CLI configuration. Show whether it applies to this + checkout or the shared project when the configuration scope is settled. +- Avoid recording routine tool calls, every edit, or repeated status reports. +- Apply the policy to existing installations through the managed instruction + update path as well as fresh setup; changing templates alone is insufficient. +- Add bounded, relevant timeline retrieval to the agent workflow, using the + task's files or subject rather than loading the entire log on every turn. +- Repair the existing CLI `timeline --type` mapping and the MCP timeline help's + unsupported event kinds while improving retrieval. +- Preserve history. Promote durable conclusions into maintained knowledge + explicitly, with their source retained; do not automatically accept every + historical note as current truth. +- Keep optional agent notes separate from mandatory workflow Activity and + recovery audit records. A quiet policy must never suppress those records. + +The exact CLI/configuration shape will be chosen after the existing read and +configuration surfaces are inspected. No new session-tracking service is needed. + +## Scope limits + +- A small audited Relay follow-up is optional after core Relay fixes; broad + editing, reassignment, and reopening are deferred. +- Full Context Review, personalized Catch Up, semantic conflict detection, + organization-wide runtime/distribution, and a guided setup skill are deferred. +- New graph edges and attribution must come from actual records; missing or + unverified information stays visible as such. +- Git remains the sharing layer. A published working-tree artifact does not + prove commit, push, receipt, or another teammate's checkout state. + +## Verification and review + +Finish each phase with focused tests, typechecking, and a review of the changed +boundary. Build and browser-check Hub/package changes. Keep Windows byte +identity and inode changes separate. Run the complete relevant release checks +after integration; retain existing resource budgets and require the established +pinned Windows/Linux CI evidence before release where local checks cannot +provide it. Do not widen a budget merely to fit a change. + +Update this plan with actual results and remaining work as phases finish. diff --git a/packages/hub-contracts/src/index.test.ts b/packages/hub-contracts/src/index.test.ts index 8f51687c..c602a376 100644 --- a/packages/hub-contracts/src/index.test.ts +++ b/packages/hub-contracts/src/index.test.ts @@ -55,6 +55,8 @@ import { WikiEntityIdSchema, WikiEntityListRequestSchema, WikiEntityListResponseSchema, + WikiGraphResponseSchema, + WikiGroundedCodeResponseSchema, WikiRelationsRequestSchema, } from "./index.js"; @@ -1260,6 +1262,28 @@ describe("Hub API contracts", () => { truncated: false, }; expect(WikiEntityListResponseSchema.safeParse(page).success).toBe(true); + const graph = { + indexedRevision: page.indexedRevision, observedAt: page.observedAt, + nodes: [summary], relations: [], + coverage: { nodeLimit: 100, relationLimit: 500, nodesTruncated: false, relationsTruncated: false }, + }; + expect(WikiGraphResponseSchema.safeParse(graph).success).toBe(true); + expect(WikiGraphResponseSchema.safeParse({ ...graph, nodes: [summary, summary] }).success).toBe(false); + expect(WikiGraphResponseSchema.safeParse({ ...graph, nodes: Array.from({ length: 101 }, (_, index) => ({ ...summary, id: `mx_${String(index).padStart(26, "0")}` })) }).success).toBe(false); + const relation = { type: "related_to", source: { id, kind: "architecture", title: null }, target: { id, kind: "architecture", title: null }, note: null }; + expect(WikiGraphResponseSchema.safeParse({ ...graph, relations: Array(501).fill(relation) }).success).toBe(false); + expect(WikiGraphResponseSchema.safeParse({ ...graph, relations: [{ ...relation, target: { ...relation.target, id: "mx_01K4FAM7W8N9R3T5Y6Q2ZBCHJE" } }] }).success).toBe(false); + const code = { + indexedRevision: page.indexedRevision, observedAt: page.observedAt, entityId: id, + graphRevision: null, groundings: [{ requestedNode: "function:queue", resolvedNode: null, health: "unverified", symbol: null }], truncated: false, + }; + expect(WikiGroundedCodeResponseSchema.safeParse(code).success).toBe(true); + expect(WikiGroundedCodeResponseSchema.safeParse({ ...code, groundings: Array(51).fill(code.groundings[0]) }).success).toBe(false); + const symbol = { id: "function:queue", symbolKind: "function", name: "queue", qualifiedName: "queue", language: "typescript", path: "src/queue.ts", startLine: 1, endLine: 4, route: "/code/symbols/function%3Aqueue" }; + const resolvedCode = { ...code, graphRevision: "c".repeat(64), groundings: [{ requestedNode: "function:queue", resolvedNode: "function:queue", health: "fresh", symbol }] }; + expect(WikiGroundedCodeResponseSchema.safeParse(resolvedCode).success).toBe(true); + expect(WikiGroundedCodeResponseSchema.safeParse({ ...resolvedCode, graphRevision: null }).success).toBe(false); + expect(WikiGroundedCodeResponseSchema.safeParse({ ...resolvedCode, groundings: [{ ...resolvedCode.groundings[0], resolvedNode: "function:other" }] }).success).toBe(false); expect(CodeKnowledgeResponseSchema.safeParse({ ...page, items: [{ entity: summary, matchedNodes: ["function:queue"] }], diff --git a/packages/hub-contracts/src/index.ts b/packages/hub-contracts/src/index.ts index 5486aefb..5812da86 100644 --- a/packages/hub-contracts/src/index.ts +++ b/packages/hub-contracts/src/index.ts @@ -2737,6 +2737,48 @@ export const WikiRelationSchema = z.object({ note: wikiDisplayText(2_048, 0).nullable(), }).strict(); +/** A bounded whole-Context view, never a join of separately observed pages. */ +export const WikiGraphResponseSchema = z.object({ + indexedRevision: revision, + observedAt: isoTimestamp, + nodes: z.array(WikiEntitySummarySchema).max(100), + relations: z.array(WikiRelationSchema).max(500), + coverage: z.object({ + nodeLimit: z.literal(100), + relationLimit: z.literal(500), + nodesTruncated: z.boolean(), + relationsTruncated: z.boolean(), + }).strict(), +}).strict().superRefine((value, context) => { + const ids = new Set(value.nodes.map((node) => node.id)); + if (ids.size !== value.nodes.length) { + context.addIssue({ code: z.ZodIssueCode.custom, path: ["nodes"], message: "Context nodes must have distinct identities." }); + } + if (value.relations.some((relation) => !ids.has(relation.source.id) || !ids.has(relation.target.id))) { + context.addIssue({ code: z.ZodIssueCode.custom, path: ["relations"], message: "Context relationships must connect included nodes." }); + } +}); + +export const WikiGroundedCodeResponseSchema = z.object({ + indexedRevision: revision, + observedAt: isoTimestamp, + entityId: WikiEntityIdSchema, + graphRevision: revision.nullable(), + groundings: z.array(z.object({ + requestedNode: wikiDisplayText(512), + resolvedNode: wikiDisplayText(512).nullable(), + health: WikiGroundingHealthSchema, + symbol: GraphSymbolSchema.nullable(), + }).strict()).max(50), + truncated: z.boolean(), +}).strict().superRefine((value, context) => { + for (const grounding of value.groundings) { + if (grounding.symbol !== null && (value.graphRevision === null || grounding.symbol.id !== grounding.resolvedNode)) { + context.addIssue({ code: z.ZodIssueCode.custom, path: ["groundings"], message: "A code symbol requires its matching resolved identity and Graph revision." }); + } + } +}); + export const WikiRelationHitSchema = z.object({ direction: z.enum(["outgoing", "incoming"]), relation: WikiRelationSchema, @@ -3253,6 +3295,8 @@ export type WikiRelationHit = z.infer; export type WikiRelationsRequest = z.infer; export type WikiBacklinksRequest = z.infer; export type WikiRelationsResponse = z.infer; +export type WikiGraphResponse = z.infer; +export type WikiGroundedCodeResponse = z.infer; export type WikiBacklinksResponse = z.infer; export type CodeKnowledgeRequest = z.infer; export type CodeKnowledgeHit = z.infer; diff --git a/packages/hub-web/src/api/client.ts b/packages/hub-web/src/api/client.ts index 1b1d0976..1d696cb6 100644 --- a/packages/hub-web/src/api/client.ts +++ b/packages/hub-web/src/api/client.ts @@ -31,6 +31,8 @@ import { TeamWorkstreamIdSchema, TeamWorkstreamListResponseSchema, TeamWorkstreamSchema, + WikiGraphResponseSchema, + WikiGroundedCodeResponseSchema, WikiBacklinksResponseSchema, WikiEntityDetailResponseSchema, WikiEntityIdSchema, @@ -91,6 +93,8 @@ import type { TeamWorkstream, TeamWorkstreamListRequest, TeamWorkstreamListResponse, + WikiGraphResponse, + WikiGroundedCodeResponse, WikiBacklinksRequest, WikiBacklinksResponse, WikiEntityDetailResponse, @@ -187,6 +191,8 @@ export interface HubApi { getActivity(request: ActivityRequest): Promise; search(request: SearchRequest): Promise; getCodeSymbol(id: string, request: CodeWorkspaceRequest): Promise; + wikiGraph(): Promise; + getWikiGroundedCode(id: string): Promise; listWikiEntities(request: WikiEntityListRequest): Promise; getWikiEntity(id: string): Promise; getWikiRelations(id: string, request: WikiRelationsRequest): Promise; @@ -550,6 +556,14 @@ export class HttpHubApi implements HubApi { ); } + wikiGraph(): Promise { + return this.#request("/wiki/graph", WikiGraphResponseSchema); + } + + getWikiGroundedCode(id: string): Promise { + return this.#request(`/wiki/entities/${encodeURIComponent(assertSafeWikiEntityId(id))}/code`, WikiGroundedCodeResponseSchema); + } + listWikiEntities(request: WikiEntityListRequest): Promise { const params = new URLSearchParams({ limit: String(request.limit) }); if (request.kind) params.set("kind", request.kind); diff --git a/packages/hub-web/src/api/types.ts b/packages/hub-web/src/api/types.ts index 0de019fe..1056d2f1 100644 --- a/packages/hub-web/src/api/types.ts +++ b/packages/hub-web/src/api/types.ts @@ -112,6 +112,8 @@ export type { TeamWorkstreamListRequest, TeamWorkstreamListResponse, TeamWorkstreamState, + WikiGraphResponse, + WikiGroundedCodeResponse, WikiSearchResult, WikiBacklinksRequest, WikiBacklinksResponse, diff --git a/packages/hub-web/src/app/App.test.tsx b/packages/hub-web/src/app/App.test.tsx index 82620de3..261e6e74 100644 --- a/packages/hub-web/src/app/App.test.tsx +++ b/packages/hub-web/src/app/App.test.tsx @@ -28,7 +28,7 @@ describe("Project Hub routes", () => { it.each([ ["/", fixtureOverviewHeading], ["/search", "Search"], - ["/knowledge", "Knowledge"], + ["/knowledge", "Context"], ["/code", "Code"], ["/workstreams", "Workstreams"], ["/specs", "Specs"], @@ -68,28 +68,22 @@ describe("Project Hub routes", () => { const primary = within(sidebar).getByRole("navigation", { name: "Primary" }); expect(within(primary).getAllByRole("link").map((link) => link.querySelector("span")?.textContent)).toEqual([ "Overview", - "Knowledge", - "Specs", + "Context", "Code", - "Workstreams", - "Inbox", "Relays", "Activity", ]); expect(within(primary).getByRole("region", { name: "Project Memory" })).toHaveTextContent( - "KnowledgeSpecsCode", + "ContextCode", ); expect(within(within(primary).getByRole("region", { name: "Teamwork" })) .getAllByRole("link") .map((link) => link.querySelector("span")?.textContent)) - .toEqual(["Workstreams", "Inbox", "Relays", "Activity"]); - const comingSoon = within(primary).getByRole("region", { name: "Coming Soon" }); - expect(within(comingSoon).queryByRole("link", { name: /Playbooks/u })).not.toBeInTheDocument(); - await user.click(within(comingSoon).getByRole("button", { name: "Coming Soon" })); - expect(within(comingSoon).getAllByRole("link").map((link) => link.querySelector("span")?.textContent)) - .toEqual(["Playbooks", "Catch Up"]); - expect(within(comingSoon).getByRole("link", { name: "Playbooks Soon" })).toHaveAttribute("href", "/playbooks"); - expect(within(comingSoon).getByRole("link", { name: "Catch Up Soon" })).toHaveAttribute("href", "/catch-up"); + .toEqual(["Relays", "Activity"]); + expect(within(primary).queryByRole("region", { name: "Coming Soon" })).not.toBeInTheDocument(); + for (const label of ["Specs", "Workstreams", "Inbox", "Playbooks", "Catch Up"]) { + expect(within(primary).queryByRole("link", { name: new RegExp(`^${label}`, "u") })).not.toBeInTheDocument(); + } const utilities = within(sidebar).getByRole("navigation", { name: "Project utilities" }); expect(within(utilities).getAllByRole("link").map((link) => link.textContent)).toEqual([ @@ -110,19 +104,15 @@ describe("Project Hub routes", () => { const projectMemory = screen.getByRole("button", { name: "Project Memory" }); const teamwork = screen.getByRole("button", { name: "Teamwork" }); - const comingSoon = screen.getByRole("button", { name: "Coming Soon" }); const system = screen.getByRole("button", { name: /^System/u }); expect(projectMemory).toHaveAttribute("aria-expanded", "true"); expect(teamwork).toHaveAttribute("aria-expanded", "true"); - expect(comingSoon).toHaveAttribute("aria-expanded", "false"); expect(system).toHaveAttribute("aria-expanded", "false"); await user.click(projectMemory); - await user.click(comingSoon); await user.click(system); expect(projectMemory).toHaveAttribute("aria-expanded", "false"); expect(teamwork).toHaveAttribute("aria-expanded", "true"); - expect(comingSoon).toHaveAttribute("aria-expanded", "true"); expect(system).toHaveAttribute("aria-expanded", "true"); first.unmount(); @@ -130,16 +120,12 @@ describe("Project Hub routes", () => { await screen.findByRole("heading", { level: 1, name: fixtureOverviewHeading }); expect(screen.getByRole("button", { name: "Project Memory" })).toHaveAttribute("aria-expanded", "true"); expect(screen.getByRole("button", { name: "Teamwork" })).toHaveAttribute("aria-expanded", "true"); - expect(screen.getByRole("button", { name: "Coming Soon" })).toHaveAttribute("aria-expanded", "false"); expect(screen.getByRole("button", { name: /^System/u })).toHaveAttribute("aria-expanded", "false"); }); it.each([ - ["/knowledge/mx_01K36WVM6H7JK8M9NPQRSTVVWX", "Project Memory", "Knowledge"], - ["/specs/mx_01K36WVM6H7JK8M9NPQRSTVVWX", "Project Memory", "Specs"], + ["/knowledge/mx_01K36WVM6H7JK8M9NPQRSTVVWX", "Project Memory", "Context"], ["/code/symbols/sym.createHubServer", "Project Memory", "Code"], - ["/playbooks", "Coming Soon", "Playbooks"], - ["/catch-up", "Coming Soon", "Catch Up"], ["/jobs", "System", "Jobs"], ])("opens the active group and marks its nested route for %s", async (route, group, link) => { renderRoute(route); @@ -156,7 +142,7 @@ describe("Project Hub routes", () => { await user.click(disclosure); expect(disclosure).toHaveAttribute("aria-expanded", "false"); expect(disclosure).toHaveAttribute("data-active", "true"); - expect(screen.queryByRole("link", { name: "Knowledge" })).not.toBeInTheDocument(); + expect(screen.queryByRole("link", { name: "Context" })).not.toBeInTheDocument(); }); it("reopens a group when navigation enters one of its routes", async () => { @@ -285,7 +271,7 @@ describe("Project Hub routes", () => { await screen.findByRole("heading", { level: 1, name: fixtureOverviewHeading }); expect(within(screen.getByRole("link", { name: /Relays/u })).getByText("Unavailable")).toBeVisible(); - expect(within(screen.getByRole("link", { name: /^Inbox/u })).queryByText("Unavailable")).not.toBeInTheDocument(); + expect(within(screen.getByRole("link", { name: "Context" })).queryByText("Unavailable")).not.toBeInTheDocument(); await user.click(screen.getByRole("button", { name: /^System/u })); expect(within(screen.getByRole("link", { name: /Jobs/u })).getByText("Unavailable")).toBeVisible(); }); @@ -313,7 +299,7 @@ describe("Project Hub routes", () => { expect(await screen.findByText("Ada Lovelace")).toBeVisible(); const repositoryBar = screen.getByRole("banner", { name: "Repository context" }); expect(within(repositoryBar).getByText(initialHome.repository.name)).toBeVisible(); - expect(screen.getByLabelText("3 proposals awaiting team review.")).toBeVisible(); + expect(screen.getByLabelText("2 open Relays for you.")).toBeVisible(); // The Hub's only outbound link. `target="_blank"` without // `rel="noopener noreferrer"` would hand the opened tab a handle on this @@ -438,11 +424,10 @@ describe("Project Hub routes", () => { it("links Overview focus, team memory, context, and active operation to exact supported routes", async () => { renderRoute("/"); const focus = await screen.findByRole("region", { name: "Attention" }); - expect(within(focus).getByRole("button", { name: "Open Inbox" })).toHaveAttribute( - "href", - "/inbox?view=review&proposal=proposal_01000000000000000000001720", - ); - expect(within(focus).getByText("Take the handoff waiting for you").closest("a")).toHaveAttribute( + expect(screen.getByRole("button", { name: "Explore Context" })).toHaveAttribute("href", "/knowledge"); + expect(within(focus).getByRole("button", { name: "View Relays" })).toHaveAttribute("href", "/relays"); + expect(within(focus).queryByRole("button", { name: "Open Inbox" })).not.toBeInTheDocument(); + expect(within(focus).getByRole("button", { name: "Open handoff" })).toHaveAttribute( "href", "/relays?view=mine&state=open&relay=relay_01000000000000000000000001", ); @@ -463,7 +448,7 @@ describe("Project Hub routes", () => { expect(screen.getByRole("link", { name: "Activity" })).toBeVisible(); expect(screen.getByRole("link", { name: "Team" })).toHaveAttribute("href", "/members"); - expect(screen.getByRole("link", { name: /^Inbox/u })).toHaveAttribute("href", "/inbox"); + expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); expect(screen.getByRole("link", { name: /^Relays/u })).toHaveAttribute("href", "/relays"); expect(screen.queryByRole("region", { name: "Project sections" })).not.toBeInTheDocument(); expect(screen.queryByRole("heading", { name: "Recent jobs" })).not.toBeInTheDocument(); diff --git a/packages/hub-web/src/app/App.tsx b/packages/hub-web/src/app/App.tsx index 489be9b6..349035f0 100644 --- a/packages/hub-web/src/app/App.tsx +++ b/packages/hub-web/src/app/App.tsx @@ -10,7 +10,7 @@ import { DesktopRequired, HubLayout } from "./HubLayout"; const HomePage = lazy(async () => ({ default: (await import("../pages/HomePage")).HomePage })); const SearchPage = lazy(async () => ({ default: (await import("../pages/SearchPage")).SearchPage })); const CodePage = lazy(async () => ({ default: (await import("../pages/SearchPage")).CodePage })); -const KnowledgePage = lazy(async () => ({ default: (await import("../pages/KnowledgePage")).KnowledgePage })); +const KnowledgePage = lazy(async () => ({ default: (await import("../pages/ContextPage")).ContextPage })); const KnowledgeDetailPage = lazy(async () => ({ default: (await import("../pages/KnowledgePage")).KnowledgeDetailPage })); const SymbolPage = lazy(async () => ({ default: (await import("../pages/SymbolPage")).SymbolPage })); const RoadmapPage = lazy(async () => ({ default: (await import("../pages/CapabilityPage")).RoadmapPage })); diff --git a/packages/hub-web/src/app/HubSidebar.test.tsx b/packages/hub-web/src/app/HubSidebar.test.tsx index 888c3275..f695bf4b 100644 --- a/packages/hub-web/src/app/HubSidebar.test.tsx +++ b/packages/hub-web/src/app/HubSidebar.test.tsx @@ -49,11 +49,10 @@ describe("HubSidebar dynamic state", () => { const { capabilities, home } = await fixtureData(); renderSidebar({ capabilities, home: homeWithCounts(home, count) }); - const inbox = screen.getByRole("link", { name: /^Inbox/u }); + expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); const relays = screen.getByRole("link", { name: /^Relays/u }); const system = screen.getByRole("button", { name: /^System/u }); const cases = [ - [inbox, `${count} proposals awaiting team review.`], [relays, `${count} open Relays for you.`], [system, `${count} active system operations.`], ] as const; @@ -72,7 +71,7 @@ describe("HubSidebar dynamic state", () => { const { capabilities, home } = await fixtureData(); const first = renderSidebar({ capabilities }); - expect(screen.getByRole("link", { name: "Inbox" })).toBeVisible(); + expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); expect(screen.getByRole("link", { name: "Relays" })).toBeVisible(); expect(screen.getByRole("button", { name: "System" })).toBeVisible(); expect(screen.getByText("Set team identity")).toBeVisible(); @@ -89,7 +88,7 @@ describe("HubSidebar dynamic state", () => { }, }); - expect(screen.getByRole("link", { name: "Inbox" })).toBeVisible(); + expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); expect(screen.getByRole("link", { name: "Relays" })).toBeVisible(); expect(screen.queryByText("Unavailable")).not.toBeInTheDocument(); }); @@ -97,29 +96,25 @@ describe("HubSidebar dynamic state", () => { it("lets capability unavailability win over counts and exposes its reason as a tooltip", async () => { const user = userEvent.setup(); const { capabilities, home } = await fixtureData(); - const reason = "Inbox reads are disconnected."; + const reason = "Relay reads are disconnected."; renderSidebar({ capabilities: { ...capabilities, - inbox: { - ...capabilities.inbox, - read: { availability: "unavailable", reason }, - }, relays: { ...capabilities.relays, - read: { availability: "unavailable", reason: "Relay reads are disconnected." }, + read: { availability: "unavailable", reason }, }, jobs: { availability: "unavailable", reason: "Job reads are disconnected." }, }, home: homeWithCounts(home, 9), }); - const inbox = screen.getByRole("link", { name: "Inbox Unavailable" }); - expect(inbox).toHaveAttribute("href", "/inbox"); - expect(inbox).toHaveAccessibleDescription(reason); - expect(within(inbox).getByText("Unavailable")).toBeVisible(); - expect(within(inbox).queryByLabelText("9 proposals awaiting team review.")).not.toBeInTheDocument(); - inbox.focus(); + const relays = screen.getByRole("link", { name: "Relays Unavailable" }); + expect(relays).toHaveAttribute("href", "/relays"); + expect(relays).toHaveAccessibleDescription(reason); + expect(within(relays).getByText("Unavailable")).toBeVisible(); + expect(within(relays).queryByLabelText("9 open Relays for you.")).not.toBeInTheDocument(); + relays.focus(); expect(await screen.findByRole("tooltip")).toHaveTextContent(reason); await user.keyboard("{Escape}"); expect(screen.queryByRole("tooltip")).not.toBeInTheDocument(); diff --git a/packages/hub-web/src/app/HubSidebar.tsx b/packages/hub-web/src/app/HubSidebar.tsx index 5b6a1380..0d0746a3 100644 --- a/packages/hub-web/src/app/HubSidebar.tsx +++ b/packages/hub-web/src/app/HubSidebar.tsx @@ -30,7 +30,6 @@ type ExpansionState = Record; const LOCALITY_EXPLANATION = "MEX runs on this device. Canonical team records are shared when committed and pushed; drafts and indexes remain local to this checkout."; const countLabels: Record string> = { - inbox: (count) => `${count} proposals awaiting team review.`, relays: (count) => `${count} open Relays for you.`, "active-jobs": (count) => `${count} active system operations.`, }; @@ -51,7 +50,6 @@ function initialExpansion(pathname: string): ExpansionState { }), { "project-memory": false, teamwork: false, - "coming-soon": false, system: false, }); } @@ -76,11 +74,6 @@ function countBadge(count: number | undefined, source: NavigationCountSource): R function itemCount(home: HomeResponse | undefined, item: NavigationItem): number | undefined { if (!home || !item.countSource) return undefined; - if (item.countSource === "inbox") { - return home.attention.inbox.availability === "available" - ? home.attention.inbox.teamReviewCount - : undefined; - } if (item.countSource === "relays") { return home.attention.relays.availability === "available" ? home.attention.relays.readyToTakeCount + home.attention.relays.inYourHandsCount @@ -129,8 +122,6 @@ function NavigationLink({ ) : runtimeUnavailable ? ( Unavailable - ) : item.availability.kind === "coming-soon" ? ( - Soon ) : item.countSource ? ( countBadge(itemCount(home, item), item.countSource) ) : null} diff --git a/packages/hub-web/src/app/JobLifecycleObserver.test.tsx b/packages/hub-web/src/app/JobLifecycleObserver.test.tsx index 29f6c247..a47ac94d 100644 --- a/packages/hub-web/src/app/JobLifecycleObserver.test.tsx +++ b/packages/hub-web/src/app/JobLifecycleObserver.test.tsx @@ -1,5 +1,6 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query"; import { act, render, waitFor } from "@testing-library/react"; +import type { ReactNode } from "react"; import { describe, expect, it, vi } from "vitest"; import type { HubApi } from "../api/client"; import { HubApiProvider } from "../api/context"; @@ -32,17 +33,79 @@ class FakeBroadcastChannel { } } -function renderObserver(api: HubApi, queryClient: QueryClient, channelScope?: string) { +function renderObserver(api: HubApi, queryClient: QueryClient, channelScope?: string, children?: ReactNode) { return render( + {children} , ); } +const contextKeys = [ + ["wiki-graph"], + ["context-detail", "mx_selected", "same-wiki-revision"], + ["context-code", "mx_selected", "same-wiki-revision"], +] as const; + +function ContextRead({ queryKey, read }: { + queryKey: readonly string[]; + read(): Promise<{ indexedRevision: string; observation: number }>; +}) { + useQuery({ queryKey, queryFn: read, staleTime: Infinity }); + return null; +} + describe("JobLifecycleObserver", () => { + it.each(["graph_refresh", "graph_rebuild", "wiki_refresh", "wiki_rebuild"] as const)( + "refreshes mounted Context reads after successful %s even when the Wiki revision is unchanged", + async (kind) => { + const fixture = createFixtureApi(); + const jobs = await fixture.getJobs(); + const original = jobs.items.find((job) => job.state === "running"); + if (!original) throw new Error("Expected a running fixture job."); + let current = { ...original, kind }; + let publish: ((job: typeof original) => void) | undefined; + const subscribeToJob = vi.fn((_id: string, callback: (job: typeof original) => void) => { + publish = callback; + return { close() {} }; + }); + const api = { + getJobs: vi.fn(async () => ({ items: [current], nextCursor: null })), + subscribeToJob, + } as unknown as HubApi; + let observation = 0; + const readers = contextKeys.map(() => vi.fn(async () => ({ + indexedRevision: "same-wiki-revision", observation, + }))); + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + const rendered = renderObserver(api, queryClient, undefined, contextKeys.map((queryKey, index) => ( + + ))); + try { + await waitFor(() => { + expect(subscribeToJob).toHaveBeenCalled(); + for (const key of contextKeys) expect(queryClient.getQueryData(key)).toMatchObject({ observation: 0 }); + }); + await act(async () => publish?.({ ...current, progress: { completed: 2, total: 4 } })); + for (const read of readers) expect(read).toHaveBeenCalledOnce(); + + observation = 1; + current = { ...current, state: "succeeded", phase: "publish", finishedAt: "2026-08-26T12:01:00.000Z" }; + await act(async () => publish?.(current)); + await waitFor(() => { + for (const key of contextKeys) expect(queryClient.getQueryData(key)).toEqual({ indexedRevision: "same-wiki-revision", observation: 1 }); + }); + for (const read of readers) expect(read).toHaveBeenCalledTimes(2); + } finally { + rendered.unmount(); + queryClient.clear(); + } + }, + ); + it("loads lifecycle state once without registering a timer poll", async () => { const getJobs = vi.fn().mockResolvedValue({ items: [], nextCursor: null }); const subscribeToJob = vi.fn(); diff --git a/packages/hub-web/src/app/JobLifecycleObserver.tsx b/packages/hub-web/src/app/JobLifecycleObserver.tsx index 29d51dfc..29581f42 100644 --- a/packages/hub-web/src/app/JobLifecycleObserver.tsx +++ b/packages/hub-web/src/app/JobLifecycleObserver.tsx @@ -29,6 +29,9 @@ export async function invalidateGraphReads(queryClient: QueryClient): Promise{location.pathname}{location.search}; +} + +function renderContext(overrides: Partial = {}, route = "/knowledge") { + const api = Object.assign(createFixtureApi(), overrides); + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } }); + return { api, queryClient, ...render( + + + + + + + + , + ) }; +} + +describe("Context graph page", () => { + it("shows all 30 entities, including disconnected sections, without requesting a list page or details", async () => { + const fixture = createFixtureApi(); + const graph = await fixture.wikiGraph(); + const extra = Array.from({ length: 27 }, (_, index) => ({ + ...graph.nodes[0], id: `mx_${String(index).padStart(26, "0")}`, kind: "component", + title: `Unlinked section ${index + 1}`, route: `/knowledge/mx_${String(index).padStart(26, "0")}`, + location: { path: ".mex/context/architecture.md", startLine: 50 + index * 3, endLine: 52 + index * 3 }, + })); + const wikiGraph = vi.fn(async () => ({ ...graph, nodes: [...graph.nodes, ...extra] })); + const listWikiEntities = vi.fn(fixture.listWikiEntities.bind(fixture)); + const getWikiEntity = vi.fn(fixture.getWikiEntity.bind(fixture)); + const getWikiGroundedCode = vi.fn(fixture.getWikiGroundedCode.bind(fixture)); + const getCodeSymbol = vi.fn(fixture.getCodeSymbol.bind(fixture)); + renderContext({ wikiGraph, listWikiEntities, getWikiEntity, getWikiGroundedCode, getCodeSymbol }); + + expect(await screen.findByRole("heading", { level: 1, name: "Context" })).toBeVisible(); + const canvas = await screen.findByLabelText("Context graph"); + for (const node of [...graph.nodes, ...extra]) { + expect(within(canvas).getByRole("button", { name: `${node.title} · ${node.kind}` })).toBeVisible(); + } + expect(screen.getByText(/30 entities · \d+ links/)).toBeVisible(); + expect(wikiGraph).toHaveBeenCalledOnce(); + expect(listWikiEntities).not.toHaveBeenCalled(); + expect(getWikiEntity).not.toHaveBeenCalled(); + expect(getWikiGroundedCode).not.toHaveBeenCalled(); + expect(getCodeSymbol).not.toHaveBeenCalled(); + }); + + it("switches between graph and the existing paginated list", async () => { + const user = userEvent.setup(); + const fixture = createFixtureApi(); + const listWikiEntities = vi.fn(fixture.listWikiEntities.bind(fixture)); + renderContext({ listWikiEntities }); + await screen.findByRole("button", { name: HUB_NODE }); + await user.click(screen.getByRole("button", { name: "List" })); + expect(await screen.findByRole("button", { name: "Load more Knowledge" })).toBeVisible(); + expect(screen.queryByLabelText("Context graph")).not.toBeInTheDocument(); + expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?view=list"); + expect(listWikiEntities).toHaveBeenCalledOnce(); + await user.click(screen.getByRole("button", { name: "Graph" })); + expect(await screen.findByRole("button", { name: HUB_NODE })).toBeVisible(); + expect(screen.getByRole("button", { name: "Graph" })).toHaveAttribute("aria-pressed", "true"); + }); + + it("reveals direct code on selection, preserves its Wiki context, and clears on Escape without fetching source bodies", async () => { + const user = userEvent.setup(); + const fixture = createFixtureApi(); + const getWikiEntity = vi.fn(fixture.getWikiEntity.bind(fixture)); + const getWikiGroundedCode = vi.fn(fixture.getWikiGroundedCode.bind(fixture)); + const getCodeSymbol = vi.fn(fixture.getCodeSymbol.bind(fixture)); + renderContext({ getWikiEntity, getWikiGroundedCode, getCodeSymbol }); + await user.click(await screen.findByRole("button", { name: HUB_NODE })); + const sidebar = within(screen.getByRole("complementary", { name: "Context details" })); + expect(await sidebar.findByText(/Every indexed response belongs to one stable revision/)).toBeVisible(); + expect(sidebar.getByRole("link", { name: "Open full record" })).toHaveAttribute("href", `/knowledge/${HUB_ID}`); + const satellite = await screen.findByRole("button", { name: CODE_NODE }); + await user.click(satellite); + expect(sidebar.getByRole("heading", { name: "createHubServer" })).toBeVisible(); + expect(sidebar.getByRole("link", { name: "Open in Code" })).toHaveAttribute("href", "/code/symbols/sym.createHubServer"); + expect(sidebar.getByText("createHubServer(options: HubServerOptions): Promise")).toBeVisible(); + expect(screen.getByRole("button", { name: HUB_NODE })).toHaveAttribute("aria-pressed", "true"); + expect(sidebar.getByRole("button", { name: "Back to Project Hub read boundaries" })).toBeVisible(); + await user.keyboard("{Escape}"); + expect(sidebar.getByRole("heading", { name: "Follow a connection" })).toBeVisible(); + expect(screen.queryByRole("button", { name: CODE_NODE })).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: HUB_NODE })).toHaveAttribute("aria-pressed", "false"); + expect(getWikiEntity).toHaveBeenCalledExactlyOnceWith(HUB_ID); + expect(getWikiGroundedCode).toHaveBeenCalledExactlyOnceWith(HUB_ID); + expect(getCodeSymbol).not.toHaveBeenCalled(); + }); + + it("replaces code satellites when another Wiki entity is selected and distinguishes no grounding from unavailable code", async () => { + const user = userEvent.setup(); + renderContext(); + await user.click(await screen.findByRole("button", { name: HUB_NODE })); + await screen.findByRole("button", { name: CODE_NODE }); + await user.click(screen.getByRole("button", { name: "One snapshot per graph request · decision" })); + const sidebar = within(screen.getByRole("complementary", { name: "Context details" })); + expect(await sidebar.findByText("No explicit code grounding recorded.")).toBeVisible(); + expect(sidebar.queryByText("Code index unavailable. Groundings are unverified.")).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: CODE_NODE })).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: "One snapshot per graph request · decision" })).toHaveAttribute("aria-pressed", "true"); + }); + + it.each(["detail", "code"] as const)("hides mismatched %s evidence and code until the graph is reloaded", async (mismatch) => { + const user = userEvent.setup(); + const fixture = createFixtureApi(); + renderContext({ + getWikiEntity: async (id) => { + const result = await fixture.getWikiEntity(id); + return mismatch === "detail" ? { ...result, indexedRevision: "f".repeat(64) } : result; + }, + getWikiGroundedCode: async (id) => { + const result = await fixture.getWikiGroundedCode(id); + return mismatch === "code" ? { ...result, indexedRevision: "f".repeat(64) } : result; + }, + }); + await user.click(await screen.findByRole("button", { name: HUB_NODE })); + const sidebar = within(screen.getByRole("complementary", { name: "Context details" })); + expect(await sidebar.findByRole("heading", { name: "Context changed" })).toBeVisible(); + expect(sidebar.queryByText(/Every indexed response belongs to one stable revision/)).not.toBeInTheDocument(); + expect(sidebar.queryByRole("link", { name: "Open in Code" })).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: CODE_NODE })).not.toBeInTheDocument(); + await user.click(sidebar.getByRole("button", { name: "Reload graph" })); + expect(await sidebar.findByRole("heading", { name: "Follow a connection" })).toBeVisible(); + }); + + it.each([ + ["missing", "b".repeat(64)], + ["unverified", null], + ] as const)("shows a %s grounding honestly without inventing a symbol", async (health, graphRevision) => { + const user = userEvent.setup(); + const fixture = createFixtureApi(); + renderContext({ getWikiGroundedCode: async (id) => ({ + ...await fixture.getWikiGroundedCode(id), graphRevision, + groundings: [{ requestedNode: "sym.unavailable", resolvedNode: null, health, symbol: null }], + }) }); + await user.click(await screen.findByRole("button", { name: HUB_NODE })); + const sidebar = within(screen.getByRole("complementary", { name: "Context details" })); + expect(await sidebar.findByText(`sym.unavailable · ${health} · code unavailable`)).toBeVisible(); + expect(screen.queryByRole("button", { name: / · code · / })).not.toBeInTheDocument(); + if (graphRevision === null) expect(sidebar.getByText("Code index unavailable. Groundings are unverified.")).toBeVisible(); + else expect(sidebar.queryByText("Code index unavailable. Groundings are unverified.")).not.toBeInTheDocument(); + }); + + it("keeps a safe sidebar error independent from the trusted graph and code projection", async () => { + const user = userEvent.setup(); + renderContext({ getWikiEntity: async () => { throw new Error("sqlite failure at /private/secret.db"); } }); + await user.click(await screen.findByRole("button", { name: HUB_NODE })); + const sidebar = within(screen.getByRole("complementary", { name: "Context details" })); + expect(await sidebar.findByRole("heading", { name: "Context unavailable" })).toBeVisible(); + expect(await screen.findByRole("button", { name: CODE_NODE })).toBeVisible(); + expect(screen.queryByText(/private\/secret/)).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: HUB_NODE })).toBeVisible(); + }); + + it("reports graph errors safely and still offers the list fallback", async () => { + const user = userEvent.setup(); + renderContext({ wikiGraph: async () => { throw new HubApiError({ type: "about:blank", title: "Stale Wiki", status: 409, code: "INDEX_STALE", detail: "Recorded knowledge changed. Inspect Health before refreshing.", requestId: "context_test" }); } }); + expect(await screen.findByRole("heading", { name: "The Context index is stale" })).toBeVisible(); + expect(screen.getByRole("link", { name: "Open Health" })).toHaveAttribute("href", "/health"); + await user.click(screen.getByRole("button", { name: "List" })); + expect(await screen.findByRole("button", { name: "Load more Knowledge" })).toBeVisible(); + }); + + it("reports a partial graph and keeps type filtering from hiding disconnected units", async () => { + const user = userEvent.setup(); + const fixture = createFixtureApi(); + const graph = await fixture.wikiGraph(); + renderContext({ wikiGraph: async () => ({ ...graph, relations: [], coverage: { ...graph.coverage, relationsTruncated: true } }) }); + expect(await screen.findByText(/Partial graph: up to 100 entities and 500 relationships are shown/)).toBeVisible(); + await user.click(screen.getByRole("button", { name: "Architecture" })); + expect(screen.getByRole("button", { name: "One snapshot per graph request · decision" })).toBeVisible(); + expect(screen.getByRole("button", { name: "One snapshot per graph request · decision" })).toHaveAttribute("data-dimmed", "true"); + await user.click(screen.getByRole("button", { name: "One snapshot per graph request · decision" })); + expect(await screen.findByText("No relationships in this graph.")).toBeVisible(); + }); + + it("keeps an unavailable Wiki capability from requesting graph or selected data", async () => { + const fixture = createFixtureApi(); + const capabilities = await fixture.getCapabilities(); + const wikiGraph = vi.fn(fixture.wikiGraph.bind(fixture)); + const getWikiEntity = vi.fn(fixture.getWikiEntity.bind(fixture)); + renderContext({ wikiGraph, getWikiEntity, getCapabilities: async () => ({ + ...capabilities, wiki: { ...capabilities.wiki, read: { availability: "unavailable", reason: "Wiki migration requires review." } }, + }) }); + expect(await screen.findByRole("heading", { name: "Context unavailable" })).toBeVisible(); + expect(screen.getByText("Wiki migration requires review.")).toBeVisible(); + expect(wikiGraph).not.toHaveBeenCalled(); + expect(getWikiEntity).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/hub-web/src/app/knowledge-pages.test.tsx b/packages/hub-web/src/app/knowledge-pages.test.tsx index 2a07ef92..6fa24cfc 100644 --- a/packages/hub-web/src/app/knowledge-pages.test.tsx +++ b/packages/hub-web/src/app/knowledge-pages.test.tsx @@ -40,9 +40,9 @@ function renderRoute(route: string, api: HubApi = createFixtureApi()) { describe("Read-only Knowledge browse", () => { it("renders real summaries and loads an older page without replacing trusted rows", async () => { const user = userEvent.setup(); - renderRoute("/knowledge"); + renderRoute("/knowledge?view=list"); - expect(await screen.findByRole("heading", { level: 1, name: "Knowledge" })).toBeVisible(); + expect(await screen.findByRole("heading", { level: 1, name: "Context" })).toBeVisible(); expect(await screen.findByText("Project Hub read boundaries")).toBeVisible(); expect(screen.getByText("One snapshot per graph request")).toBeVisible(); expect(screen.getByText("Some entries carry bounded diagnostics.")).toBeVisible(); @@ -54,26 +54,26 @@ describe("Read-only Knowledge browse", () => { it("keeps filters in URL history and makes text search an explicit independent mode", async () => { const user = userEvent.setup(); - renderRoute("/knowledge"); + renderRoute("/knowledge?view=list"); await screen.findByText("Project Hub read boundaries"); await user.selectOptions(screen.getByLabelText("Lifecycle"), "promoted"); await user.click(screen.getByRole("button", { name: "Apply" })); - await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?lifecycle=promoted")); + await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?view=list&lifecycle=promoted")); const filteredSummary = await screen.findByText("Filtered Knowledge records"); expect(filteredSummary.parentElement).toHaveFocus(); expect(screen.queryByText("Review immutable activity")).not.toBeInTheDocument(); await user.type(screen.getByRole("searchbox", { name: "Search titles, summaries, and bodies" }), "hub"); await user.click(screen.getByRole("button", { name: "Apply" })); - await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?q=hub")); + await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?view=list&q=hub")); expect(screen.getByTestId("location")).not.toHaveTextContent("lifecycle"); expect(await screen.findByText("Knowledge results for “hub”")).toBeVisible(); }); it("preserves a complete canonical topic ID through the URL-backed filter", async () => { const user = userEvent.setup(); - renderRoute("/knowledge"); + renderRoute("/knowledge?view=list"); await screen.findByText("Project Hub read boundaries"); const topic = screen.getByLabelText("Topic ID"); @@ -82,7 +82,7 @@ describe("Read-only Knowledge browse", () => { await user.click(screen.getByRole("button", { name: "Apply" })); await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent( - `/knowledge?topic=${GRAPH_TOPIC_ID}`, + `/knowledge?view=list&topic=${GRAPH_TOPIC_ID}`, )); expect(screen.getByText("Project Hub read boundaries")).toBeVisible(); expect(screen.queryByText("One snapshot per graph request")).not.toBeInTheDocument(); @@ -94,7 +94,7 @@ describe("Read-only Knowledge browse", () => { const listWikiEntities = vi.fn((request: Parameters[0]) => ( request.cursor ? Promise.reject(new Error("private path /tmp/wiki.sqlite")) : fixture.listWikiEntities(request) )); - renderRoute("/knowledge", apiWith({ listWikiEntities })); + renderRoute("/knowledge?view=list", apiWith({ listWikiEntities })); expect(await screen.findByText("Project Hub read boundaries")).toBeVisible(); await user.click(screen.getByRole("button", { name: "Load more Knowledge" })); @@ -112,13 +112,13 @@ describe("Read-only Knowledge browse", () => { const listWikiEntities = vi.fn((request: Parameters[0]) => ( request.cursor ? olderPage : fixture.listWikiEntities(request) )); - renderRoute("/knowledge", apiWith({ listWikiEntities })); + renderRoute("/knowledge?view=list", apiWith({ listWikiEntities })); await screen.findByText("Project Hub read boundaries"); await user.click(screen.getByRole("button", { name: "Load more Knowledge" })); await user.type(screen.getByLabelText("Kind"), "decision"); await user.click(screen.getByRole("button", { name: "Apply" })); - await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?kind=decision")); + await waitFor(() => expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?view=list&kind=decision")); expect(await screen.findByText("One snapshot per graph request")).toBeVisible(); expect(screen.queryByText("Project Hub read boundaries")).not.toBeInTheDocument(); @@ -133,14 +133,14 @@ describe("Read-only Knowledge browse", () => { it("distinguishes a successful filtered-empty read from an unavailable index", async () => { const user = userEvent.setup(); - renderRoute("/knowledge"); + renderRoute("/knowledge?view=list"); await screen.findByText("Project Hub read boundaries"); await user.type(screen.getByLabelText("Kind"), "nonexistent"); await user.click(screen.getByRole("button", { name: "Apply" })); expect(await screen.findByRole("heading", { name: "No Knowledge matches these filters" })).toBeVisible(); - expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?kind=nonexistent"); + expect(screen.getByTestId("location")).toHaveTextContent("/knowledge?view=list&kind=nonexistent"); }); it.each([ @@ -150,7 +150,7 @@ describe("Read-only Knowledge browse", () => { ["MIGRATION_REQUIRED", "Knowledge migration is required"], ] as const)("projects %s through the explicit Health boundary", async (code, title) => { const error = new HubApiError({ type: "about:blank", title, status: 409, code, detail: "Safe Wiki inspection failed.", requestId: `req_${code}` }); - renderRoute("/knowledge", apiWith({ listWikiEntities: () => Promise.reject(error) })); + renderRoute("/knowledge?view=list", apiWith({ listWikiEntities: () => Promise.reject(error) })); expect(await screen.findByRole("heading", { name: title })).toBeVisible(); expect(screen.getByRole("link", { name: "Open Wiki health" })).toHaveAttribute("href", "/health"); @@ -165,7 +165,7 @@ describe("Read-only Knowledge browse", () => { if (request.cursor && conflict) return { ...response, indexedRevision: "f".repeat(64) }; return response; }); - renderRoute("/knowledge", apiWith({ listWikiEntities })); + renderRoute("/knowledge?view=list", apiWith({ listWikiEntities })); await screen.findByText("Project Hub read boundaries"); await user.click(screen.getByRole("button", { name: "Load more Knowledge" })); @@ -186,7 +186,7 @@ describe("Read-only Knowledge browse", () => { wiki: { ...capabilities.wiki, read: { availability: "unavailable", reason: "Wiki migration must be reviewed manually." } }, }), }); - renderRoute("/knowledge", api); + renderRoute("/knowledge?view=list", api); expect(await screen.findByRole("heading", { name: "Knowledge unavailable" })).toBeVisible(); expect(screen.getByText("Wiki migration must be reviewed manually.")).toBeVisible(); }); @@ -201,8 +201,7 @@ describe("Read-only Knowledge browse", () => { expect(screen.getByRole("heading", { level: 2, name: `${title} is coming soon` })).toBeVisible(); expect(screen.getByText(copy)).toBeVisible(); expect(screen.getByText("Soon", { selector: '[data-slot="badge"][role="status"]' })).toBeVisible(); - expect(screen.getByRole("button", { name: "Coming Soon" })).toHaveAttribute("aria-expanded", "true"); - expect(screen.getByRole("link", { name: `${title} Soon` })).toHaveAttribute("aria-current", "page"); + expect(screen.queryByRole("button", { name: "Coming Soon" })).not.toBeInTheDocument(); expect(screen.queryByText("Read only")).not.toBeInTheDocument(); expect(screen.queryByText("No data requested")).not.toBeInTheDocument(); }); diff --git a/packages/hub-web/src/app/navigation.ts b/packages/hub-web/src/app/navigation.ts index 105119a8..0c2ee478 100644 --- a/packages/hub-web/src/app/navigation.ts +++ b/packages/hub-web/src/app/navigation.ts @@ -1,30 +1,24 @@ import { Activity, - BookOpenText, Code2, - FileCheck2, GitPullRequestArrow, HeartPulse, - History, House, - Inbox, - ListChecks, + Network, Search, Send, UsersRound, - Workflow, type LucideIcon, } from "lucide-react"; import type { CapabilityName } from "../api/types"; -export type NavigationGroupId = "project-memory" | "teamwork" | "coming-soon" | "system"; +export type NavigationGroupId = "project-memory" | "teamwork" | "system"; export type NavigationPlacement = "launcher" | "primary" | "footer"; -export type NavigationCountSource = "inbox" | "relays" | "active-jobs"; +export type NavigationCountSource = "relays" | "active-jobs"; export type NavigationAvailability = | { kind: "always" } - | { kind: "runtime"; capability: CapabilityName } - | { kind: "coming-soon" }; + | { kind: "runtime"; capability: CapabilityName }; export interface NavigationItem { id: string; @@ -48,7 +42,6 @@ export interface NavigationGroup { export const navigationGroups: readonly NavigationGroup[] = [ { id: "project-memory", label: "Project Memory", placement: "primary", defaultExpanded: true }, { id: "teamwork", label: "Teamwork", placement: "primary", defaultExpanded: true }, - { id: "coming-soon", label: "Coming Soon", placement: "primary", defaultExpanded: false }, { id: "system", label: "System", placement: "footer", defaultExpanded: false, countSource: "active-jobs" }, ]; @@ -71,22 +64,13 @@ export const navigationItems: readonly NavigationItem[] = [ }, { id: "knowledge", - label: "Knowledge", + label: "Context", path: "/knowledge", - icon: BookOpenText, + icon: Network, group: "project-memory", placement: "primary", availability: { kind: "runtime", capability: "wiki" }, }, - { - id: "specs", - label: "Specs", - path: "/specs", - icon: FileCheck2, - group: "project-memory", - placement: "primary", - availability: { kind: "runtime", capability: "specs" }, - }, { id: "code", label: "Code", @@ -96,25 +80,6 @@ export const navigationItems: readonly NavigationItem[] = [ placement: "primary", availability: { kind: "runtime", capability: "graph" }, }, - { - id: "workstreams", - label: "Workstreams", - path: "/workstreams", - icon: Workflow, - group: "teamwork", - placement: "primary", - availability: { kind: "runtime", capability: "workstreams" }, - }, - { - id: "inbox", - label: "Inbox", - path: "/inbox", - icon: Inbox, - group: "teamwork", - placement: "primary", - availability: { kind: "runtime", capability: "inbox" }, - countSource: "inbox", - }, { id: "relays", label: "Relays", @@ -134,24 +99,6 @@ export const navigationItems: readonly NavigationItem[] = [ placement: "primary", availability: { kind: "runtime", capability: "activity" }, }, - { - id: "playbooks", - label: "Playbooks", - path: "/playbooks", - icon: ListChecks, - group: "coming-soon", - placement: "primary", - availability: { kind: "coming-soon" }, - }, - { - id: "catch-up", - label: "Catch Up", - path: "/catch-up", - icon: History, - group: "coming-soon", - placement: "primary", - availability: { kind: "coming-soon" }, - }, { id: "team", label: "Team", diff --git a/packages/hub-web/src/app/page-states.test.tsx b/packages/hub-web/src/app/page-states.test.tsx index 2e683003..51b46720 100644 --- a/packages/hub-web/src/app/page-states.test.tsx +++ b/packages/hub-web/src/app/page-states.test.tsx @@ -61,13 +61,12 @@ describe("Home states", () => { it("renders established focus, semantic team memory, stale context, and an exact active operation", async () => { renderRoute("/", createFixtureApi({ overviewFixture: "established" })); - expect(await screen.findByRole("heading", { name: "Review 3 proposed Spec changes" })).toBeVisible(); + expect(await screen.findByRole("heading", { name: "Take the handoff waiting for you" })).toBeVisible(); + expect(screen.queryByText("Review 3 proposed Spec changes")).not.toBeInTheDocument(); expect(screen.getByRole("heading", { name: "Attention" })).toBeVisible(); - expect(screen.getByRole("button", { name: "Open Inbox" })).toHaveAttribute( - "href", - "/inbox?view=review&proposal=proposal_01000000000000000000001720", - ); - expect(screen.getByText("Take the handoff waiting for you").closest("a")).toHaveAttribute( + expect(screen.getByRole("button", { name: "Explore Context" })).toHaveAttribute("href", "/knowledge"); + expect(screen.getByRole("button", { name: "View Relays" })).toHaveAttribute("href", "/relays"); + expect(screen.getByRole("button", { name: "Open handoff" })).toHaveAttribute( "href", "/relays?view=mine&state=open&relay=relay_01000000000000000000000001", ); @@ -162,10 +161,8 @@ describe("Home states", () => { await user.click(screen.getByRole("button", { name: "View technical details for Attention" })); expect(screen.getByText("RELAY_LEGACY_PUBLICATION_TIME")).toBeVisible(); expect(screen.getByText("Relay diagnostics truncated").nextElementSibling).toHaveTextContent("Yes"); - expect(screen.getByText("INBOX_SOURCE_TRUNCATED")).toBeVisible(); - expect(screen.getByText("Inbox corpus truncated").nextElementSibling).toHaveTextContent("Yes"); - expect(screen.getByText("Inbox source truncated").nextElementSibling).toHaveTextContent("Yes"); - expect(screen.getByText("Inbox diagnostics truncated").nextElementSibling).toHaveTextContent("Yes"); + expect(screen.queryByText("Inbox focus unavailable")).not.toBeInTheDocument(); + expect(screen.queryByText("INBOX_SOURCE_TRUNCATED")).not.toBeInTheDocument(); }); it("renders detached and unborn Graph repository observations without shell fallback", async () => { @@ -197,7 +194,7 @@ describe("Home states", () => { expect(await screen.findByText("You’re caught up")).toBeVisible(); expect(screen.getByRole("heading", { name: "Overview" })).toBeVisible(); - expect(screen.getByRole("button", { name: "Browse project memory" })).toHaveAttribute("href", "/search"); + expect(screen.getByRole("button", { name: "Browse shared knowledge" })).toHaveAttribute("href", "/knowledge"); expect(screen.getAllByText("Fresh", { selector: "dd" })).toHaveLength(2); expect(screen.getAllByText("Fresh", { selector: "strong" })).toHaveLength(2); expect(screen.queryByRole("heading", { name: "Active operation" })).not.toBeInTheDocument(); @@ -254,7 +251,7 @@ describe("Home states", () => { expect(await screen.findByText("Resolve who you’re working as")).toBeVisible(); expect(screen.getByText("The referenced member no longer exists.")).toBeVisible(); expect(screen.getByRole("button", { name: "Review identity" })).toHaveAttribute("href", "/members"); - expect(screen.getByText("Review 3 proposed Spec changes")).toBeVisible(); + expect(screen.queryByText("Review 3 proposed Spec changes")).not.toBeInTheDocument(); }); it("renders degraded parse composition and determinate or indeterminate operations exactly", async () => { diff --git a/packages/hub-web/src/components/ContextGraphCanvas.tsx b/packages/hub-web/src/components/ContextGraphCanvas.tsx new file mode 100644 index 00000000..489a9d7d --- /dev/null +++ b/packages/hub-web/src/components/ContextGraphCanvas.tsx @@ -0,0 +1,111 @@ +import { useEffect, useId, useMemo, useRef, useState, type CSSProperties } from "react"; +import { Maximize2, Minus, Plus } from "lucide-react"; +import { CONTEXT_EDGE_LIMIT, CONTEXT_NODE_LIMIT, contextCurve, layoutCodeSatellites, layoutContextGraph, type ContextEdge, type ContextNode } from "../lib/context-graph"; +import styles from "../styles/context-graph.module.css"; + +export interface ContextCodeNode { id: string; title: string; health: string } +interface Props { + nodes: readonly ContextNode[]; + edges: readonly ContextEdge[]; + selectedId: string | null; + selectedCodeId: string | null; + codeNodes: readonly ContextCodeNode[]; + highlightedIds?: ReadonlySet; + onSelect(id: string): void; + onSelectCode(id: string): void; + onClear(): void; +} + +const kinds = ["architecture", "component", "decision", "convention", "pattern", "guide", "risk", "fact", "task", "topic", "spec", "requirement", "constraint", "acceptance_criterion"]; +export function contextTypeColor(kind: string): string { return `var(--context-type-${Math.max(0, kinds.indexOf(kind)) % 6})`; } + +export function ContextGraphCanvas({ nodes, edges, selectedId, selectedCodeId, codeNodes, highlightedIds, onSelect, onSelectCode, onClear }: Props) { + const root = useRef(null); + const id = useId().replace(/:/g, ""); + const [size, setSize] = useState({ width: 760, height: 620 }); + const [view, setView] = useState({ x: 0, y: 0, scale: 1 }); + const drag = useRef<{ x: number; y: number; startX: number; startY: number; moved: boolean } | null>(null); + const boundedNodes = useMemo(() => nodes.slice(0, CONTEXT_NODE_LIMIT), [nodes]); + const world = useMemo(() => ({ width: Math.max(size.width, Math.ceil(Math.sqrt(boundedNodes.length * 22000))), height: Math.max(size.height, Math.ceil(boundedNodes.length / 5) * 110 + 60) }), [size, boundedNodes.length]); + const layout = useMemo(() => layoutContextGraph(boundedNodes, edges, world.width, world.height), [boundedNodes, edges, world]); + const satellites = useMemo(() => layoutCodeSatellites(codeNodes.map((node) => node.id), selectedId ? layout.get(selectedId) : undefined, layout, world.width, world.height), [codeNodes, selectedId, layout, world]); + const worldHeight = Math.max(world.height, ...[...satellites.values()].map((point) => point.y + 55)); + const links = useMemo(() => edges.slice(0, CONTEXT_EDGE_LIMIT).filter((edge) => layout.has(edge.source) && layout.has(edge.target)), [edges, layout]); + const neighbors = new Set(links.filter((edge) => edge.source === selectedId || edge.target === selectedId).flatMap((edge) => [edge.source, edge.target])); + + function fit() { + const scale = Math.min(1, size.width / world.width, size.height / worldHeight); + setView({ x: (size.width - world.width * scale) / 2, y: (size.height - worldHeight * scale) / 2, scale }); + } + function zoom(factor: number) { + setView((current) => { + const floor = Math.min(.35, size.width / world.width, size.height / worldHeight); + const scale = Math.max(floor, Math.min(2.5, current.scale * factor)); + const ratio = scale / current.scale; + return { scale, x: size.width / 2 - (size.width / 2 - current.x) * ratio, y: size.height / 2 - (size.height / 2 - current.y) * ratio }; + }); + } + useEffect(() => { + const element = root.current; + if (!element || typeof ResizeObserver === "undefined") return; + const observer = new ResizeObserver(([entry]) => { + if (entry && entry.contentRect.width > 0 && entry.contentRect.height > 0) setSize({ width: entry.contentRect.width, height: entry.contentRect.height }); + }); + observer.observe(element); + return () => observer.disconnect(); + }, []); + useEffect(() => { + const scale = Math.min(1, size.width / world.width, size.height / world.height); + setView({ x: (size.width - world.width * scale) / 2, y: (size.height - world.height * scale) / 2, scale }); + }, [size, world]); + useEffect(() => { + const element = root.current; + if (!element) return; + const wheel = (event: WheelEvent) => { + if (!event.ctrlKey && !event.metaKey) return; + event.preventDefault(); zoom(event.deltaY > 0 ? .9 : 1.1); + }; + element.addEventListener("wheel", wheel, { passive: false }); + return () => element.removeEventListener("wheel", wheel); + }, [size, world.width, worldHeight]); + + return
{ if (event.key === "Escape") { onClear(); event.stopPropagation(); } }} + onPointerDown={(event) => { + if (event.button !== 0 || (event.target as Element).closest("button,a")) return; + event.currentTarget.setPointerCapture?.(event.pointerId); + drag.current = { x: event.clientX, y: event.clientY, startX: view.x, startY: view.y, moved: false }; + }} + onPointerMove={(event) => { + if (!drag.current) return; + const dx = event.clientX - drag.current.x, dy = event.clientY - drag.current.y; + if (Math.abs(dx) + Math.abs(dy) > 4) drag.current.moved = true; + const { startX, startY } = drag.current; + setView((current) => ({ ...current, x: startX + dx, y: startY + dy })); + }} + onPointerUp={() => { if (drag.current && !drag.current.moved) onClear(); drag.current = null; }} + onPointerCancel={() => { drag.current = null; }}> +
+ + {boundedNodes.map((node) => { + const point = layout.get(node.id)!; + const style = { left: point.x, top: point.y, "--node-color": contextTypeColor(node.kind) } as CSSProperties; + return ; + })} + {codeNodes.filter((node) => satellites.has(node.id)).map((node) => { + const point = satellites.get(node.id)!; + const parent = selectedId ? layout.get(selectedId) : undefined; + return ; + })} +
+
+ + + +
+

Drag to pan · Ctrl / ⌘ scroll to zoom{codeNodes.length ? " · Fit graph to see every code node" : ""}

+
; +} diff --git a/packages/hub-web/src/dev/fixture-api.ts b/packages/hub-web/src/dev/fixture-api.ts index ae5720f2..c267d46c 100644 --- a/packages/hub-web/src/dev/fixture-api.ts +++ b/packages/hub-web/src/dev/fixture-api.ts @@ -60,6 +60,8 @@ import type { WikiBacklinksResponse, WikiEntityDetailResponse, WikiEntityListRequest, + WikiGraphResponse, + WikiGroundedCodeResponse, WikiEntityListResponse, WikiEntitySummary, WikiRelationsRequest, @@ -3456,6 +3458,20 @@ class FixtureHubApi implements HubApi { return Promise.reject(error); } } + wikiGraph(): Promise { + const relations = wikiEntities.flatMap((entity) => [...wikiRelations(entity.id).items.map((hit) => hit.relation), ...wikiBacklinks(entity.id).items]); + return Promise.resolve({ indexedRevision: wikiRevision, observedAt: timestamp(0), nodes: wikiEntities, + relations: [...new Map(relations.map((edge) => [`${edge.source.id}:${edge.target.id}:${edge.type}`, edge])).values()], + coverage: { nodeLimit: 100, relationLimit: 500, nodesTruncated: false, relationsTruncated: false } }); + } + getWikiGroundedCode(id: string): Promise { + const detail = wikiDetail(id); + return Promise.resolve({ indexedRevision: wikiRevision, observedAt: timestamp(0), entityId: id, graphRevision, + groundings: detail.groundings.items.flatMap((grounding) => grounding.requestedNode ? [{ + requestedNode: grounding.requestedNode, resolvedNode: grounding.resolvedNode, health: grounding.health, + symbol: graphSymbols.find((symbol) => symbol.id === grounding.resolvedNode) ?? null, + }] : []), truncated: detail.groundings.truncated }); + } listWikiEntities(request: WikiEntityListRequest): Promise { const filtered = wikiEntities.filter((entity) => ( (!request.kind || entity.kind === request.kind) diff --git a/packages/hub-web/src/lib/context-graph.test.ts b/packages/hub-web/src/lib/context-graph.test.ts new file mode 100644 index 00000000..a8c99591 --- /dev/null +++ b/packages/hub-web/src/lib/context-graph.test.ts @@ -0,0 +1,139 @@ +import { describe, expect, it } from "vitest"; +import { + CONTEXT_NODE_LIMIT, + layoutCodeSatellites, + layoutContextGraph, + type ContextEdge, + type ContextNode, + type GraphPoint, +} from "./context-graph"; + +const types = ["architecture", "component", "convention", "decision", "guide", "pattern"]; +const nodes: readonly ContextNode[] = Array.from({ length: 30 }, (_, index) => ({ + id: `knowledge-${String(index).padStart(2, "0")}`, + title: `Repository knowledge ${index + 1}`, + kind: types[index % types.length]!, +})); +// Thirteen connected records and seventeen unlinked records, including sections. +const edges: readonly ContextEdge[] = Array.from({ length: 36 }, (_, index) => ({ + source: nodes[index % 13]!.id, + target: nodes[(index % 13 + 3 + Math.floor(index / 13)) % 13]!.id, + type: "related_to", +})); + +function expectFinite(point: GraphPoint): void { + expect(Number.isFinite(point.x)).toBe(true); + expect(Number.isFinite(point.y)).toBe(true); +} + +describe("Context knowledge layout", () => { + it("keeps the same positions when browse results arrive in a different order", () => { + const original = layoutContextGraph(nodes, edges, 960, 720); + const reordered = layoutContextGraph([...nodes].reverse(), edges, 960, 720); + + expect(reordered).toEqual(original); + }); + + it("keeps the same positions when recorded relationships arrive in a different order", () => { + const original = layoutContextGraph(nodes, edges, 960, 720); + const reordered = layoutContextGraph(nodes, [...edges].reverse(), 960, 720); + + expect(reordered).toEqual(original); + }); + + it.each([ + [720, 720], + [960, 720], + ])("includes all thirty records within a %i by %i canvas", (width, height) => { + const result = layoutContextGraph(nodes, edges, width, height); + + expect(result.size).toBe(30); + for (const node of nodes) { + const point = result.get(node.id); + expect(point).toBeDefined(); + expectFinite(point!); + expect(point!.x).toBeGreaterThanOrEqual(60); + expect(point!.x).toBeLessThanOrEqual(width - 60); + expect(point!.y).toBeGreaterThanOrEqual(30); + expect(point!.y).toBeLessThanOrEqual(height - 30); + } + expect(new Set([...result.values()].map(({ x, y }) => `${x},${y}`)).size).toBe(30); + for (const unlinked of nodes.slice(13)) expect(result.has(unlinked.id)).toBe(true); + }); + + it("handles empty knowledge and bounds a larger corpus", () => { + expect(layoutContextGraph([], [], 960, 720).size).toBe(0); + const largeCorpus = Array.from({ length: CONTEXT_NODE_LIMIT + 10 }, (_, index) => ({ + id: `large-${index}`, + title: `Knowledge ${index}`, + kind: "pattern", + })); + const result = layoutContextGraph(largeCorpus, [], 960, 720); + + expect(result.size).toBe(CONTEXT_NODE_LIMIT); + for (const point of result.values()) expectFinite(point); + }); + + it("ignores links whose endpoints cannot appear in the knowledge layout", () => { + const original = layoutContextGraph(nodes, edges, 960, 720); + const withUnavailableTargets = layoutContextGraph(nodes, [ + ...edges, + { source: nodes[0]!.id, target: "missing-record", type: "related_to" }, + { source: "missing-record", target: nodes[1]!.id, type: "related_to" }, + { source: nodes[0]!.id, target: nodes[0]!.id, type: "related_to" }, + ], 960, 720); + + expect(withUnavailableTargets).toEqual(original); + }); +}); + +describe("Context code expansion", () => { + it("places a small direct grounding set inside the canvas without moving knowledge", () => { + const base = layoutContextGraph(nodes, edges, 960, 720); + const before = structuredClone(base); + for (const point of base.values()) Object.freeze(point); + const parent = base.get(nodes[0]!.id); + const expanded = layoutCodeSatellites(["symbol-a", "symbol-b"], parent, base, 960, 720); + + expect([...expanded.keys()]).toEqual(["symbol-a", "symbol-b"]); + for (const point of expanded.values()) { + expectFinite(point); + expect(point.x).toBeGreaterThanOrEqual(74); + expect(point.x).toBeLessThanOrEqual(960 - 74); + expect(point.y).toBeGreaterThanOrEqual(36); + expect(point.y).toBeLessThanOrEqual(720 - 36); + for (const knowledge of base.values()) { + expect(Math.abs(point.x - knowledge.x) >= 132 || Math.abs(point.y - knowledge.y) >= 68).toBe(true); + } + } + expect(base).toEqual(before); + expect(layoutCodeSatellites(["symbol-a", "symbol-b"], parent, base, 960, 720)).toEqual(expanded); + layoutCodeSatellites(["another-symbol"], base.get(nodes[1]!.id), base, 960, 720); + expect(base).toEqual(before); + }); + + it("deduplicates and bounds a dense expansion without moving the base layout", () => { + const base = layoutContextGraph(nodes, edges, 720, 720); + const before = structuredClone(base); + const ids = Array.from({ length: 70 }, (_, index) => `symbol-${index}`); + const expanded = layoutCodeSatellites([ids[0]!, ...ids], base.get(nodes[0]!.id), base, 720, 720); + + expect(expanded.size).toBe(50); + for (const point of expanded.values()) { + expectFinite(point); + expect(point.x).toBeGreaterThanOrEqual(0); + expect(point.x).toBeLessThanOrEqual(720); + expect(point.y).toBeGreaterThanOrEqual(0); + // Dense code sets can extend the canvas; retained work must still be finite. + expect(point.y).toBeLessThanOrEqual(720 + 50 * 100); + } + expect(base).toEqual(before); + }); + + it("shows no satellites without a selected knowledge record or without groundings", () => { + const base = layoutContextGraph(nodes, edges, 960, 720); + + expect(layoutCodeSatellites(["symbol-a"], undefined, base, 960, 720).size).toBe(0); + expect(layoutCodeSatellites([], base.get(nodes[0]!.id), base, 960, 720).size).toBe(0); + }); +}); diff --git a/packages/hub-web/src/lib/context-graph.ts b/packages/hub-web/src/lib/context-graph.ts new file mode 100644 index 00000000..2f5ce331 --- /dev/null +++ b/packages/hub-web/src/lib/context-graph.ts @@ -0,0 +1,87 @@ +export interface ContextNode { id: string; title: string; kind: string } +export interface ContextEdge { source: string; target: string; type: string; note?: string | null } +export interface GraphPoint { x: number; y: number } +export const CONTEXT_NODE_LIMIT = 100; +export const CONTEXT_EDGE_LIMIT = 500; + +function hash(value: string): number { + let result = 2166136261; + for (const character of value) result = Math.imul(result ^ character.charCodeAt(0), 16777619); + return result >>> 0; +} + +/** A finite layout pass. Index order and selection never change the base positions. */ +export function layoutContextGraph(nodes: readonly ContextNode[], edges: readonly ContextEdge[], width: number, height: number): Map { + const entries = [...nodes.slice(0, CONTEXT_NODE_LIMIT)].sort((a, b) => a.id.localeCompare(b.id)); + const kinds = [...new Set(entries.map((node) => node.kind))].sort(); + const points = entries.map((node, index) => { + const angle = kinds.indexOf(node.kind) * Math.PI * 2 / Math.max(kinds.length, 1) - Math.PI / 2; + const spread = (hash(node.id) % 1000) / 1000; + return { + id: node.id, + x: width / 2 + Math.cos(angle) * width * .22 + Math.cos(index * 2.39996) * (40 + spread * width * .15), + y: height / 2 + Math.sin(angle) * height * .22 + Math.sin(index * 2.39996) * (40 + spread * height * .15), + }; + }); + const byId = new Map(points.map((point) => [point.id, point])); + const links = edges.slice(0, CONTEXT_EDGE_LIMIT).sort((a, b) => `${a.source}:${a.target}:${a.type}`.localeCompare(`${b.source}:${b.target}:${b.type}`)).flatMap((edge) => { + const a = byId.get(edge.source), b = byId.get(edge.target); + return a && b && a !== b ? [[a, b] as const] : []; + }); + for (let pass = 0; pass < 220; pass++) { + if (pass < 100) for (const [a, b] of links) { + const dx = b.x - a.x, dy = b.y - a.y; + if (Math.hypot(dx, dy) > 175) { + a.x += dx * .003; a.y += dy * .003; + b.x -= dx * .003; b.y -= dy * .003; + } + } + for (let i = 0; i < points.length; i++) for (let j = i + 1; j < points.length; j++) { + const a = points[i]!, b = points[j]!; + const dx = b.x - a.x, dy = b.y - a.y; + const overlapX = 124 - Math.abs(dx), overlapY = 72 - Math.abs(dy); + if (overlapX > 0 && overlapY > 0) { + if (overlapX / 124 < overlapY / 72) { + const push = overlapX * .51 * (dx >= 0 ? 1 : -1); + a.x -= push; b.x += push; + } else { + const push = overlapY * .51 * (dy >= 0 ? 1 : -1); + a.y -= push; b.y += push; + } + } + } + for (const point of points) { + point.x = Math.max(66, Math.min(width - 66, point.x)); + point.y = Math.max(36, Math.min(height - 45, point.y)); + } + } + return new Map(points.map(({ id, x, y }) => [id, { x, y }])); +} + +/** Satellites occupy free space; the underlying knowledge layout stays fixed. */ +export function layoutCodeSatellites(ids: readonly string[], parent: GraphPoint | undefined, base: ReadonlyMap, width: number, height: number): Map { + if (!parent) return new Map(); + const occupied = [...base.values()].map((point) => ({ ...point, width: 116, height: 64 })); + const result = new Map(); + for (const [index, id] of [...new Set(ids)].slice(0, 50).entries()) { + let chosen: GraphPoint | undefined; + for (let radius = 90; radius <= Math.max(width, height) && !chosen; radius += 18) { + for (let step = 0; step < 32; step++) { + const angle = step * Math.PI / 16 + index * .15; + const point = { x: parent.x + Math.cos(angle) * radius, y: parent.y + Math.sin(angle) * radius }; + if (point.x < 78 || point.x > width - 78 || point.y < 40 || point.y > height - 50) continue; + if (!occupied.some((other) => Math.abs(point.x - other.x) < (148 + other.width) / 2 + 5 && Math.abs(point.y - other.y) < (72 + other.height) / 2 + 5)) { + chosen = point; break; + } + } + } + chosen ??= { x: 90 + (index % Math.max(1, Math.floor(width / 180))) * 180, y: height + 55 + Math.floor(index / Math.max(1, Math.floor(width / 180))) * 90 }; + result.set(id, chosen); + occupied.push({ ...chosen, width: 148, height: 72 }); + } + return result; +} + +export function contextCurve(a: GraphPoint, b: GraphPoint, bend = 16): string { + return `M ${a.x} ${a.y - 15} Q ${(a.x + b.x) / 2 + bend} ${(a.y + b.y) / 2 - 15 - bend} ${b.x} ${b.y - 15}`; +} diff --git a/packages/hub-web/src/pages/ContextPage.tsx b/packages/hub-web/src/pages/ContextPage.tsx new file mode 100644 index 00000000..cb70ebf0 --- /dev/null +++ b/packages/hub-web/src/pages/ContextPage.tsx @@ -0,0 +1,124 @@ +import { lazy, Suspense, useEffect, useMemo, useState, type CSSProperties } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { Link, useOutletContext, useSearchParams } from "react-router-dom"; +import { ArrowUpRight, Network, X } from "lucide-react"; +import { useHubApi } from "../api/context"; +import { HubApiError } from "../api/client"; +import type { CapabilitiesResponse } from "../api/types"; +import { PageHeader, sentenceCase, StatePanel, StatusPill } from "../components/ui"; +import { Button, buttonVariants } from "../components/primitives/button"; +import { Input } from "../components/primitives/input"; +import { ContextGraphCanvas, contextTypeColor } from "../components/ContextGraphCanvas"; +import styles from "../styles/context.module.css"; + +const KnowledgeList = lazy(async () => ({ default: (await import("./KnowledgePage")).KnowledgePage })); +const emptyNodes: never[] = []; + +function ReadProblem({ error, retry }: { error: unknown; retry(): void }) { + const problem = error instanceof HubApiError ? error.problem : null; + return Open Health} />; +} + +export function ContextPage() { + const [params, setParams] = useSearchParams(); + // Existing saved list filters remain usable when opening an older link. + const list = params.get("view") === "list" || (!params.has("view") && ["q", "kind", "topic", "lifecycle", "grounding", "sourceType"].some((key) => params.has(key))); + return
+
+
+ + +
+
+ {list ? }> : } +
; +} + +function ContextExplorer() { + const api = useHubApi(); + const { capabilities } = useOutletContext<{ capabilities?: CapabilitiesResponse }>(); + const enabled = capabilities?.wiki.read.availability === "available"; + const graph = useQuery({ queryKey: ["wiki-graph"], queryFn: () => api.wikiGraph(), enabled, retry: false }); + const [selectedId, setSelectedId] = useState(null); + const [codeId, setCodeId] = useState(null); + const [codeLimit, setCodeLimit] = useState(12); + const [query, setQuery] = useState(""); + const [kind, setKind] = useState(null); + const revision = graph.data?.indexedRevision; + useEffect(() => { setSelectedId(null); setCodeId(null); }, [revision]); + const nodes = graph.data?.nodes ?? emptyNodes; + const selected = nodes.find((node) => node.id === selectedId); + const detail = useQuery({ queryKey: ["context-detail", selectedId, revision], queryFn: () => api.getWikiEntity(selectedId!), enabled: enabled && !!selected, retry: false }); + const code = useQuery({ queryKey: ["context-code", selectedId, revision], queryFn: () => api.getWikiGroundedCode(selectedId!), enabled: enabled && !!selected, retry: false }); + const conflict = !!selected && (!!detail.data && (detail.data.indexedRevision !== revision || detail.data.entity.id !== selectedId) + || !!code.data && (code.data.indexedRevision !== revision || code.data.entityId !== selectedId)); + const record = !conflict && !detail.error ? detail.data : undefined; + const bridge = !conflict && !code.error ? code.data : undefined; + const symbols = useMemo(() => [...new Map((bridge?.groundings ?? []).flatMap((item) => item.symbol ? [[item.symbol.id, { symbol: item.symbol, health: item.health }] as const] : [])).values()], [bridge]); + const codeNodes = useMemo(() => symbols.slice(0, codeLimit).map(({ symbol, health }) => ({ id: symbol.id, title: symbol.name, health })), [symbols, codeLimit]); + const edges = useMemo(() => (graph.data?.relations ?? []).map((edge) => ({ source: edge.source.id, target: edge.target.id, type: edge.type, note: edge.note })), [graph.data]); + const kinds = useMemo(() => [...new Set(nodes.map((node) => node.kind))].sort(), [nodes]); + const highlighted = useMemo(() => query.trim() || kind ? new Set(nodes.filter((node) => (!kind || node.kind === kind) && `${node.title} ${node.summary ?? ""} ${node.location.path}`.toLowerCase().includes(query.trim().toLowerCase())).map((node) => node.id)) : undefined, [nodes, query, kind]); + const activeCode = symbols.find(({ symbol }) => symbol.id === codeId); + const relations = (graph.data?.relations ?? []).filter((edge) => edge.source.id === selectedId || edge.target.id === selectedId); + function select(id: string) { setSelectedId(id); setCodeId(null); setCodeLimit(12); } + function clear() { setSelectedId(null); setCodeId(null); } + function reload() { clear(); void graph.refetch(); } + + if (!capabilities) return ; + if (!enabled) return ; + if (graph.error) return ; + if (!graph.data) return ; + if (!nodes.length) return ; + + return
{ if (event.key === "Escape") clear(); }}> +
+ +
+ + {kinds.map((type) => )} +
+ {highlighted ? `${highlighted.size} matching · ` : ""}{nodes.length} entities · {edges.length} links +
+ {graph.data.coverage.nodesTruncated || graph.data.coverage.relationsTruncated ?

Partial graph: up to 100 entities and 500 relationships are shown. Use List to browse more knowledge.

: null} +
+ + +
+
; +} diff --git a/packages/hub-web/src/pages/HomeOverview.tsx b/packages/hub-web/src/pages/HomeOverview.tsx index c11e3003..fb929d55 100644 --- a/packages/hub-web/src/pages/HomeOverview.tsx +++ b/packages/hub-web/src/pages/HomeOverview.tsx @@ -10,8 +10,8 @@ import { CircleDashed, ExternalLink, GitBranch, - Inbox, LoaderCircle, + Network, RadioTower, RefreshCw, ScrollText, @@ -21,7 +21,7 @@ import { } from "lucide-react"; import { useState, type CSSProperties, type ReactNode } from "react"; import { Link } from "react-router-dom"; -import { InboxProposalIdSchema, RelayIdSchema } from "@mex/hub-contracts/ids"; +import { RelayIdSchema } from "@mex/hub-contracts/ids"; import { useHubApi } from "../api/context"; import type { ActivityItem, OverviewResponse } from "../api/types"; import { @@ -124,14 +124,20 @@ function HomeHeader({ title="Overview" description={data ? `Last checked ${formatDate(data.observedAt)}` : undefined} actions={( - +
+ + +
)} /> ); @@ -194,15 +200,6 @@ function actorAttentionDescription(data: OverviewResponse): string { return "Review the team identity MEX uses for shared actions in this checkout."; } -function proposalRoute(source: FocusPanel["inbox"]): string { - if (source.availability !== "available") return "/inbox?view=review"; - const proposal = source.items[0]; - const parsed = proposal ? InboxProposalIdSchema.safeParse(proposal.ref.id) : null; - return parsed?.success - ? `/inbox?view=review&proposal=${encodeURIComponent(parsed.data)}` - : "/inbox?view=review"; -} - function relayRoute(source: FocusPanel["relays"], kind: "ready" | "claimed"): string { if (source.availability !== "available") return "/relays?view=mine&state=open"; const relay = kind === "ready" ? source.readyToTake[0] : source.inYourHands[0]; @@ -267,16 +264,6 @@ function buildFocusItems(data: OverviewResponse): FocusItemView[] { icon: UserRound, }); } - if (focus?.inbox.availability === "available" && focus.inbox.teamReviewCount > 0) { - const count = focus.inbox.teamReviewCount; - items.push({ - id: "inbox", - title: count === 1 ? "Review one proposed Spec change" : `Review ${count} proposed Spec changes`, - action: "Open Inbox", - route: proposalRoute(focus.inbox), - icon: Inbox, - }); - } if (focus?.relays.availability === "available" && focus.relays.readyToTakeCount > 0) { const count = focus.relays.readyToTakeCount; items.push({ @@ -335,9 +322,6 @@ function focusWarnings(data: OverviewResponse): Array<{ label: string; reason: s if (data.focus.identity.availability === "unavailable") { warnings.push({ label: "Identity focus", reason: data.focus.identity.reason }); } - if (data.focus.inbox.availability === "unavailable") { - warnings.push({ label: "Inbox focus", reason: data.focus.inbox.reason }); - } if (data.focus.relays.availability === "unavailable") { warnings.push({ label: "Relay focus", reason: data.focus.relays.reason }); } @@ -371,42 +355,6 @@ function FocusTechnicalDetails({ data }: { data: OverviewResponse }) { ))} ) :
Identity source
{data.identity.reason}
} - {focus?.inbox.availability === "available" ? ( - <> -
Inbox revision
{focus.inbox.deterministicRevision}
-
Inbox source truncated
{focus.inbox.sourceTruncated ? "Yes" : "No"}
-
Inbox diagnostics truncated
{focus.inbox.diagnosticsTruncated ? "Yes" : "No"}
- {focus.inbox.diagnostics.map((diagnostic, index) => ( -
-
{diagnostic.code}
-
{diagnostic.path ? {diagnostic.path} : diagnostic.message}
-
- ))} - - ) : null} - {focus?.inbox.availability === "unavailable" ? ( - <> -
Inbox source
{focus.inbox.reason}
- {focus.inbox.deterministicRevision ? ( -
Inbox revision
{focus.inbox.deterministicRevision}
- ) : null} - {focus.inbox.truncated !== undefined ? ( -
Inbox corpus truncated
{focus.inbox.truncated ? "Yes" : "No"}
- ) : null} - {focus.inbox.sourceTruncated !== undefined ? ( -
Inbox source truncated
{focus.inbox.sourceTruncated ? "Yes" : "No"}
- ) : null} - {focus.inbox.diagnosticsTruncated !== undefined ? ( -
Inbox diagnostics truncated
{focus.inbox.diagnosticsTruncated ? "Yes" : "No"}
- ) : null} - {focus.inbox.diagnostics?.map((diagnostic, index) => ( -
-
{diagnostic.code}
-
{diagnostic.path ? {diagnostic.path} : diagnostic.message}
-
- ))} - - ) : null} {focus?.relays.availability === "available" ? ( <>
Relay revision
{focus.relays.deterministicRevision}
@@ -458,6 +406,12 @@ function FocusCard({ data, onRetry }: { data: OverviewResponse; onRetry: () => v

Attention

+ + +
{primary && PrimaryIcon ? ( @@ -479,9 +433,9 @@ function FocusCard({ data, onRetry }: { data: OverviewResponse; onRetry: () => v You’re caught up - @@ -635,7 +589,7 @@ function LatestActivityCard({ activity, onRetry }: { activity: OverviewResponse[ No team memory yet - Shared MEX changes, including agent-prepared Spec proposals and handoffs, will appear here automatically. + Recorded team changes, handoffs, and project notes will appear here. ) : ( diff --git a/packages/hub-web/src/pages/KnowledgePage.tsx b/packages/hub-web/src/pages/KnowledgePage.tsx index 5566bf05..e8c5447b 100644 --- a/packages/hub-web/src/pages/KnowledgePage.tsx +++ b/packages/hub-web/src/pages/KnowledgePage.tsx @@ -168,10 +168,11 @@ function collectionFromSearch(response: SearchResponse): KnowledgeCollection | n }; } -function KnowledgeBrowse() { +function KnowledgeBrowse({ embedded = false }: { embedded?: boolean }) { const api = useHubApi(); const { capabilities } = useOutletContext<{ capabilities?: CapabilitiesResponse }>(); - const [params, setParams] = useSearchParams(); + const [params, updateParams] = useSearchParams(); + const setParams = (next: Record) => updateParams(params.get("view") === "list" ? { view: "list", ...next } : next); const query = (params.get("q") ?? "").trim().slice(0, 256); const activeFilters = { kind: (params.get("kind") ?? "").trim().slice(0, 128), @@ -309,7 +310,7 @@ function KnowledgeBrowse() { return (
- + {!embedded && } {!capabilities ? ( ) : capabilities.wiki.read.availability === "unavailable" ? ( @@ -787,8 +788,8 @@ function KnowledgeDetail() { ); } -export function KnowledgePage() { - return ; +export function KnowledgePage({ embedded = false }: { embedded?: boolean }) { + return ; } export function KnowledgeDetailPage() { diff --git a/packages/hub-web/src/styles/context-graph.module.css b/packages/hub-web/src/styles/context-graph.module.css new file mode 100644 index 00000000..334773e2 --- /dev/null +++ b/packages/hub-web/src/styles/context-graph.module.css @@ -0,0 +1,28 @@ +.canvas { + --context-type-0: #8eb5dc; --context-type-1: #75b8b0; --context-type-2: #cbb776; + --context-type-3: #a8bf84; --context-type-4: #c0a0dc; --context-type-5: #acb3cf; + position: relative; height: clamp(520px, 68vh, 760px); min-width: 0; overflow: hidden; + background: var(--background); touch-action: none; user-select: none; +} +.world { position: absolute; top: 0; left: 0; transform-origin: 0 0; transform: translate(var(--view-x), var(--view-y)) scale(var(--view-scale)); } +.edges { position: absolute; overflow: visible; pointer-events: none; } +.edge, .activeEdge, .groundingEdge { fill: none; stroke: var(--muted-foreground); stroke-width: .8; stroke-opacity: .26; } +.activeEdge { stroke: var(--primary); stroke-width: 1; stroke-opacity: .7; } +.groundingEdge { stroke: var(--primary); stroke-width: 1; stroke-opacity: .8; stroke-dasharray: 3 4; } +.node, .codeNode { position: absolute; width: 116px; height: 60px; padding: 28px 2px 0; transform: translate(-50%, -50%); background: none; border: 0; color: var(--foreground); cursor: pointer; text-align: center; font: 400 11px/14px var(--font-sans, "Geist", sans-serif); } +.nodeLabel { font-size: clamp(11px, calc(11px / var(--view-scale)), 16px); line-height: clamp(14px, calc(14px / var(--view-scale)), 20px); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; } +.orb { position: absolute; top: 7px; left: calc(50% - 8px); width: 16px; height: 16px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--node-color) 70%, transparent); background: color-mix(in srgb, var(--node-color) 38%, var(--background)); box-shadow: 0 0 0 4px color-mix(in srgb, var(--node-color) 7%, transparent); transition: transform 140ms, box-shadow 140ms; } +.node:hover .orb { transform: scale(1.15); } +.node[data-neighbor="true"] .orb { background: color-mix(in srgb, var(--node-color) 58%, var(--background)); } +.node[aria-pressed="true"] .orb { border: 2px solid var(--primary); box-shadow: 0 0 0 5px var(--primary-soft); } +.node[data-dimmed="true"] { opacity: .25; } +.node:focus-visible, .codeNode:focus-visible { outline: 1px solid var(--ring); outline-offset: 3px; border-radius: 4px; } +.codeNode { width: 148px; height: 72px; padding-top: 32px; font-family: "IBM Plex Mono", monospace; animation: expand 230ms cubic-bezier(.2,.8,.2,1); } +.codeOrb { position: absolute; top: 8px; left: calc(50% - 11px); width: 22px; height: 22px; border: 1px solid var(--primary); border-radius: 50%; background: var(--background); color: var(--primary); font: 11px/21px "IBM Plex Mono", monospace; } +.codeNode[aria-pressed="true"] .codeOrb { box-shadow: 0 0 0 4px var(--primary-soft); } +.controls { position: absolute; display: flex; gap: 1px; right: 16px; bottom: 16px; border: 1px solid var(--border); border-radius: 6px; background: var(--card); } +.controls button { width: 32px; height: 30px; display: grid; place-items: center; background: none; border: 0; color: var(--foreground); cursor: pointer; } +.controls button:hover { background: var(--accent); } +.hint { position: absolute; bottom: 17px; left: 16px; margin: 0; max-width: calc(100% - 145px); color: var(--muted-foreground); font-size: 10px; line-height: 16px; pointer-events: none; } +@keyframes expand { from { transform: translate(calc(-50% + var(--from-x)), calc(-50% + var(--from-y))) scale(.85); } to { transform: translate(-50%, -50%) scale(1); } } +@media (prefers-reduced-motion: reduce) { .codeNode { animation: none; } .orb { transition: none; } } diff --git a/packages/hub-web/src/styles/context.module.css b/packages/hub-web/src/styles/context.module.css new file mode 100644 index 00000000..d68415d4 --- /dev/null +++ b/packages/hub-web/src/styles/context.module.css @@ -0,0 +1,30 @@ +.page { display: grid; gap: 20px; min-width: 0; } +.heading { display: flex; gap: 20px; justify-content: space-between; align-items: center; } +.switcher { display: flex; gap: 2px; padding: 3px; border: 1px solid var(--border); border-radius: 7px; } +.explorer { --context-type-0: #8eb5dc; --context-type-1: #75b8b0; --context-type-2: #cbb776; --context-type-3: #a8bf84; --context-type-4: #c0a0dc; --context-type-5: #acb3cf; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } +.toolbar { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); } +.search { display: grid; gap: 6px; width: 210px; flex-shrink: 0; font-size: 11px; color: var(--muted-foreground); } +.legend { display: flex; gap: 5px 10px; flex: 1; flex-wrap: wrap; align-items: center; } +.legend button { display: flex; align-items: center; gap: 6px; background: none; color: var(--muted-foreground); border: 1px solid transparent; padding: 5px; border-radius: 4px; font-size: 11px; cursor: pointer; } +.legend button[aria-pressed="true"] { color: var(--foreground); border-color: var(--border); background: var(--muted); } +.legend i { display: inline-block; width: 7px; height: 7px; border-radius: 50%; } +.count { color: var(--muted-foreground); font-size: 11px; white-space: nowrap; } +.notice { padding: 12px 18px; margin: 0; border-bottom: 1px solid var(--border); font-size: 12px; color: var(--foreground); } +.workbench { display: grid; grid-template-columns: minmax(0, 1fr) 280px; } +.details { border-left: 1px solid var(--border); padding: 18px; max-height: clamp(520px, 68vh, 760px); overflow-y: auto; min-width: 0; background: var(--card); font-size: 12px; line-height: 1.6; overflow-wrap: anywhere; } +.details h2 { font-size: 18px; font-weight: 500; line-height: 1.4; margin: 6px 0 12px; letter-spacing: -.02em; } +.details h3 { font-size: 11px; font-weight: 500; color: var(--foreground); text-transform: uppercase; letter-spacing: .06em; margin: 0 0 10px; } +.details h3 span { float: right; color: var(--muted-foreground); } +.details p { color: var(--muted-foreground); margin: 10px 0; } +.details section { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border); } +.welcome { padding-top: 42px; color: var(--muted-foreground); } +.welcome h2 { margin-top: 18px; color: var(--foreground); } +.detailTop { display: flex; align-items: center; justify-content: space-between; color: var(--muted-foreground); font-size: 11px; } +.path { font: 10px/1.7 "IBM Plex Mono", monospace; overflow-wrap: anywhere; } +.badges { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 10px; color: var(--muted-foreground); } +.body { font: inherit; white-space: pre-wrap; margin: 0; color: var(--muted-foreground); } +.signature { white-space: pre-wrap; font: 11px/1.7 "IBM Plex Mono", monospace; background: var(--background); padding: 10px; border-radius: 4px; } +.recordLink { display: block; width: 100%; background: none; border: 0; border-bottom: 1px solid var(--border); text-align: left; padding: 9px 0; color: var(--foreground); font: inherit; cursor: pointer; overflow-wrap: anywhere; } +.recordLink:hover { color: var(--primary); } +.recordLink small { display: block; font-size: 10px; color: var(--muted-foreground); } +@media (max-width: 1200px) { .workbench { grid-template-columns: minmax(0, 1fr) 240px; } .toolbar { gap: 10px; } .details { padding: 14px; } .count { width: 100%; } } diff --git a/packages/hub-web/src/styles/global.css b/packages/hub-web/src/styles/global.css index 6c2ea8a7..af0ac771 100644 --- a/packages/hub-web/src/styles/global.css +++ b/packages/hub-web/src/styles/global.css @@ -6,6 +6,10 @@ @source "../app"; @source "../components"; @source "../pages"; +/* Test assertions are not production utility-class declarations. */ +@source not "../app/**/*.test.tsx"; +@source not "../components/**/*.test.tsx"; +@source not "../pages/**/*.test.tsx"; @custom-variant dark (&:is(.dark *)); diff --git a/packages/hub-web/src/styles/home.module.css b/packages/hub-web/src/styles/home.module.css index 5c144743..1fe73a7c 100644 --- a/packages/hub-web/src/styles/home.module.css +++ b/packages/hub-web/src/styles/home.module.css @@ -5,6 +5,13 @@ gap: 22px; } +.headerActions { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; +} + .liveStatus { min-height: 0; margin-top: -14px; diff --git a/scripts/release-benchmark/assets.mjs b/scripts/release-benchmark/assets.mjs index 1474792e..fd33faf9 100644 --- a/scripts/release-benchmark/assets.mjs +++ b/scripts/release-benchmark/assets.mjs @@ -8,6 +8,7 @@ const FORBIDDEN_SHELL_HINTS = [ "SearchPage", "SymbolPage", "KnowledgePage", + "ContextPage", "CapabilityPage", "WorkstreamsPage", "SpecsPage", @@ -24,6 +25,7 @@ const FORBIDDEN_HOME_HINTS = [ "SearchPage", "SymbolPage", "KnowledgePage", + "ContextPage", "CapabilityPage", "WorkstreamsPage", "SpecsPage", diff --git a/scripts/release-benchmark/browser.mjs b/scripts/release-benchmark/browser.mjs index 5e8d1511..82d74daf 100644 --- a/scripts/release-benchmark/browser.mjs +++ b/scripts/release-benchmark/browser.mjs @@ -100,11 +100,17 @@ export async function measureWorkbenchHeap({ }; } -async function assertReleaseRouteReady(page, route, teamFixture) { +export async function assertReleaseRouteReady(page, route, teamFixture) { if (route === "home") { await page.locator('[data-overview-workbench="ready"]') .waitFor({ state: "visible", timeout: PAGE_READY_TIMEOUT_MS }); } + if (route === "knowledge") { + const graph = page.getByLabel("Context graph", { exact: true }); + await graph.waitFor({ state: "visible", timeout: PAGE_READY_TIMEOUT_MS }); + await graph.getByRole("button", { name: /^Release benchmark knowledge 0000 · /u }) + .waitFor({ state: "visible", timeout: PAGE_READY_TIMEOUT_MS }); + } if (route === "workstreams") { await page.getByRole("heading", { name: "Release benchmark Workstream", exact: true }) .waitFor({ state: "visible", timeout: PAGE_READY_TIMEOUT_MS }); diff --git a/scripts/release-benchmark/hub.mjs b/scripts/release-benchmark/hub.mjs index 0fac8931..8ff85ef7 100644 --- a/scripts/release-benchmark/hub.mjs +++ b/scripts/release-benchmark/hub.mjs @@ -145,9 +145,10 @@ export async function measureCommonReads(server, auth, samples, teamFixture) { if (typeof symbol?.id !== "string") { throw new Error("The benchmark Graph fixture did not produce a searchable symbol."); } - await hubJson(server, `/api/v1/code/symbols/${encodeURIComponent(symbol.id)}?view=overview`, auth); - await hubJson(server, "/api/v1/wiki/entities?limit=25", auth); - await hubJson(server, "/api/v1/activity?limit=25", auth); + const paths = releaseCommonReadPaths(symbol.id); + await hubJson(server, paths.code, auth); + await hubJson(server, paths.knowledge, auth); + await hubJson(server, paths.activity, auth); const warmInboxDrafts = await hubJson(server, "/api/v1/inbox/drafts?limit=25", auth); const warmInboxProposals = await hubJson( server, @@ -181,7 +182,6 @@ export async function measureCommonReads(server, auth, samples, teamFixture) { summary: teamFixture.relaySummary, }); - const paths = releaseCommonReadPaths(symbol.id); const timings = Object.fromEntries(Object.keys(paths).map((name) => [name, []])); for (let sample = 0; sample < samples; sample += 1) { for (const [name, path] of Object.entries(paths)) { @@ -197,7 +197,7 @@ export function releaseCommonReadPaths(codeSymbolId) { return { search: "/api/v1/search?q=releaseBenchmarkNeedle&limit=25", code: `/api/v1/code/symbols/${encodeURIComponent(codeSymbolId)}?view=overview`, - knowledge: "/api/v1/wiki/entities?limit=25", + knowledge: "/api/v1/wiki/graph", activity: "/api/v1/activity?limit=25", inboxDrafts: "/api/v1/inbox/drafts?limit=25", inboxProposals: "/api/v1/inbox/proposals?state=pending,stale&limit=25", diff --git a/scripts/release-benchmark/release-benchmark.test.js b/scripts/release-benchmark/release-benchmark.test.js index 815eef2d..ca13ba2e 100644 --- a/scripts/release-benchmark/release-benchmark.test.js +++ b/scripts/release-benchmark/release-benchmark.test.js @@ -13,8 +13,9 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import Ajv2020 from "ajv/dist/2020.js"; import addFormats from "ajv-formats"; -import { describe, expect, it } from "vitest"; -import { assertNoForbiddenWorkbench, evaluateAssetBudgets } from "./assets.mjs"; +import { describe, expect, it, vi } from "vitest"; +import { assertNoForbiddenWorkbench, evaluateAssetBudgets, measureBuiltAssets } from "./assets.mjs"; +import { assertReleaseRouteReady } from "./browser.mjs"; import { releaseWorkbenchPaths, RELEASE_ROUTE_KEYS, @@ -223,6 +224,7 @@ describe("release benchmark contract", () => { "relayDrafts", "relays", ]); + expect(releaseCommonReadPaths("symbol/release").knowledge).toBe("/api/v1/wiki/graph"); expect(budgetsSchema.$defs.readBudgets.properties).toEqual(expect.objectContaining({ inboxDrafts: { $ref: "#/$defs/nonNegativeNumber" }, inboxProposals: { $ref: "#/$defs/nonNegativeNumber" }, @@ -233,6 +235,33 @@ describe("release benchmark contract", () => { expect(validateBudgets(budgets), JSON.stringify(validateBudgets.errors)).toBe(true); }); + it.each(["ready", "canvas unavailable", "fixture node missing"])( + "accepts only a populated Context graph before heap measurement: %s", + async (state) => { + const waitForNode = vi.fn(async () => { + if (state === "fixture node missing") throw new Error("Fixture node is not visible."); + }); + const graph = { + waitFor: vi.fn(async () => { + if (state === "canvas unavailable") throw new Error("Context graph is unavailable."); + }), + getByRole: vi.fn(() => ({ waitFor: waitForNode })), + }; + const page = { getByLabel: vi.fn(() => graph) }; + const ready = assertReleaseRouteReady(page, "knowledge", {}); + + if (state === "ready") { + await expect(ready).resolves.toBeUndefined(); + expect(waitForNode).toHaveBeenCalledWith({ state: "visible", timeout: 30_000 }); + } else { + await expect(ready).rejects.toThrow(state === "canvas unavailable" + ? "Context graph is unavailable." : "Fixture node is not visible."); + } + expect(page.getByLabel).toHaveBeenCalledWith("Context graph", { exact: true }); + if (state === "canvas unavailable") expect(graph.getByRole).not.toHaveBeenCalled(); + }, + ); + it("uses nearest-rank p95 and rejects the wrong sample count", () => { expect(summarize([7, 1, 9, 4, 2, 10, 8, 6, 5, 3], 10)).toEqual({ samples: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @@ -441,6 +470,49 @@ describe("release benchmark contract", () => { }]); }); + it("measures the default Context graph separately from its lazy knowledge list and detail", () => { + const output = mkdtempSync(join(tmpdir(), "mex-context-assets-")); + try { + mkdirSync(join(output, ".vite")); + mkdirSync(join(output, "assets")); + const pages = ["HomePage", "SearchPage", "ContextPage", "KnowledgePage", "SymbolPage", + "CapabilityPage", "WorkstreamsPage", "SpecsPage", "InboxPage", "RelayPage", + "MembersPage", "ActivityPage", "JobsPage", "HealthPage"]; + const manifest = { + "index.html": { file: "assets/index.js", isEntry: true, dynamicImports: pages }, + "graph-runtime": { file: "assets/graph.js" }, + "record-runtime": { file: "assets/record.js" }, + }; + for (const page of pages) { + manifest[page] = { + file: `assets/${page}.js`, + src: `src/pages/${page}.tsx`, + isDynamicEntry: true, + }; + } + manifest.ContextPage.imports = ["graph-runtime"]; + manifest.ContextPage.dynamicImports = ["KnowledgePage"]; + manifest.KnowledgePage.imports = ["record-runtime"]; + writeFileSync(join(output, ".vite", "manifest.json"), JSON.stringify(manifest)); + for (const record of Object.values(manifest)) { + writeFileSync(join(output, record.file), `// ${record.file}\n`); + } + + const measurement = measureBuiltAssets(output, budgets.assets); + + expect(measurement.routes.knowledge.files.map(({ file }) => file)).toEqual([ + "assets/ContextPage.js", "assets/graph.js", + ]); + expect(measurement.routes.knowledgeDetail.files.map(({ file }) => file)).toEqual([ + "assets/KnowledgePage.js", "assets/record.js", + ]); + expect(measurement.initial.files.map(({ file }) => file)).toEqual(["assets/index.js"]); + expect(measurement.routes.home.files.map(({ file }) => file)).toEqual(["assets/HomePage.js"]); + } finally { + rmSync(output, { recursive: true, force: true }); + } + }); + it("rejects forbidden workbench modules hidden behind opaque chunk keys", () => { const manifest = { "_opaque.js": { diff --git a/scripts/release-benchmark/routes.mjs b/scripts/release-benchmark/routes.mjs index 0f067a58..c4690884 100644 --- a/scripts/release-benchmark/routes.mjs +++ b/scripts/release-benchmark/routes.mjs @@ -8,7 +8,7 @@ export const RELEASE_ROUTE_MANIFEST_HINTS = Object.freeze({ home: Object.freeze(["HomePage", "hub-contracts/dist/overview"]), search: Object.freeze(["SearchPage"]), - knowledge: Object.freeze(["KnowledgePage"]), + knowledge: Object.freeze(["ContextPage"]), knowledgeDetail: Object.freeze(["KnowledgePage"]), code: Object.freeze(["SearchPage"]), codeSymbol: Object.freeze(["SymbolPage"]), diff --git a/src/graph/__tests__/application-adapter.test.ts b/src/graph/__tests__/application-adapter.test.ts index 56d3ee9d..b64fb58d 100644 --- a/src/graph/__tests__/application-adapter.test.ts +++ b/src/graph/__tests__/application-adapter.test.ts @@ -406,6 +406,85 @@ describe("RepositoryGraphPort", () => { }); }, 20_000); + it("projects at most 50 direct grounding symbols without source reads or alias substitution", async () => { + const { root, port: basePort } = await fixture(); + const target = (await basePort.searchNodes({ query: "serviceTarget", limit: 1 })).items[0]!; + const caller = (await basePort.searchNodes({ query: "serviceCaller", limit: 1 })).items[0]!; + let loads = 0; + let lookups = 0; + let sourceReads = 0; + const port = createRepositoryGraphPort(root, { + __internal: { + loadFresh: async (...args) => { + loads += 1; + const loaded = await loadFreshGraphReadSession(...args); + if (!loaded.session) return loaded; + const originalGraph = loaded.session.graph; + const graph = new Proxy(originalGraph, { + get(targetGraph, property, receiver) { + if (property === "getNode") { + return (id: string) => { + lookups += 1; + const node = originalGraph.getNode(id === "function:alias" ? target.ref.symbolId : id); + return node === null ? null : { ...node, signature: "x".repeat(5_000) }; + }; + } + return Reflect.get(targetGraph, property, receiver); + }, + }); + return { + ...loaded, + session: { + ...loaded.session, + graph, + readIndexedSource() { + sourceReads += 1; + throw new Error("Compact symbols must not request source bodies."); + }, + }, + }; + }, + }, + }); + + const symbols = await port.withFreshGroundingSnapshot((snapshot) => { + const result = snapshot.getSymbols([ + caller.ref.symbolId, + "function:missing", + target.ref.symbolId, + caller.ref.symbolId, + "function:alias", + ]); + expect(lookups).toBe(4); + expect(snapshot.getSymbols(Array.from({ length: 50 }, () => target.ref.symbolId))).toHaveLength(1); + expect(snapshot.getSymbols([])).toEqual([]); + const beforeInvalidRequests = lookups; + for (const ids of [ + Array.from({ length: 51 }, () => target.ref.symbolId), + [target.ref.symbolId, "unsafe/id"], + null as unknown as readonly string[], + ]) { + expect(() => snapshot.getSymbols(ids)).toThrowError(MexPortError); + try { + snapshot.getSymbols(ids); + } catch (error) { + expectPortCode(error, "VALIDATION_FAILED"); + } + } + expect(lookups).toBe(beforeInvalidRequests); + return result; + }); + + expect(loads).toBe(1); + expect(sourceReads).toBe(0); + expect(symbols.map((symbol) => symbol.ref.symbolId)).toEqual([caller.ref.symbolId, target.ref.symbolId]); + expect(symbols[0]).toEqual({ ...caller, signature: "x".repeat(4 * 1024) }); + expect(symbols[1]).toEqual({ ...target, signature: "x".repeat(4 * 1024) }); + expect(symbols.every((symbol) => !Object.hasOwn(symbol, "bodyHash") + && !Object.hasOwn(symbol, "fingerprint") && !Object.hasOwn(symbol, "docstring") + && !Object.hasOwn(symbol, "content"))).toBe(true); + }, 30_000); + it("holds one fresh grounding snapshot through async work and discards it on source invalidation", async () => { const { root, port: basePort } = await fixture(); const target = (await basePort.searchNodes({ query: "serviceTarget", limit: 1 })).items[0]!; @@ -434,17 +513,20 @@ describe("RepositoryGraphPort", () => { const projection = await port.withFreshGroundingSnapshot(async (snapshot) => { escaped = snapshot; const node = snapshot.getNode(target.ref.symbolId); + const symbols = snapshot.getSymbols([target.ref.symbolId]); const fingerprint = snapshot.getFingerprint(target.ref.symbolId); await Promise.resolve(); callbackSettled = true; - return { node, fingerprint }; + return { node, symbols, fingerprint }; }); expect(projection.node).toMatchObject({ id: target.ref.symbolId, filePath: "src/service.ts", }); expect(projection.fingerprint).toEqual(expect.any(String)); + expect(projection.symbols).toEqual([target]); expect(() => escaped!.getNode(target.ref.symbolId)).toThrowError(MexPortError); + expect(() => escaped!.getSymbols([target.ref.symbolId])).toThrowError(MexPortError); try { escaped!.getNode(target.ref.symbolId); } catch (error) { @@ -454,7 +536,7 @@ describe("RepositoryGraphPort", () => { callbackSettled = false; await expect(port.withFreshGroundingSnapshot(async (snapshot) => { - const buffered = snapshot.getNode(target.ref.symbolId); + const buffered = snapshot.getSymbols([target.ref.symbolId]); source(root, "src/service.ts", "export const changedDuringGrounding = true;\n"); await Promise.resolve(); callbackSettled = true; @@ -498,6 +580,14 @@ describe("RepositoryGraphPort", () => { expect((error as MexPortError).problem.detail).not.toContain("raw graph accessor failure"); return true; }); + await expect(port.withFreshGroundingSnapshot((snapshot) => { + snapshot.getSymbols(["function:1111111111111111"]); + })).rejects.toSatisfy((error) => { + expectPortCode(error, "OPERATION_INTERRUPTED"); + expect((error as MexPortError).problem.detail).not.toContain(root); + expect((error as MexPortError).problem.detail).not.toContain("raw graph accessor failure"); + return true; + }); }, 30_000); it("commits prepared grounding work only after final Graph validation and discards on invalidation", async () => { diff --git a/src/graph/application-adapter.ts b/src/graph/application-adapter.ts index a39afc6b..52c6a2c7 100644 --- a/src/graph/application-adapter.ts +++ b/src/graph/application-adapter.ts @@ -54,6 +54,7 @@ import { LANGUAGES, NODE_KINDS, type GraphNode } from "./types.js"; const MAX_CURSOR_BYTES = 4 * 1024; const MAX_QUERY_CHARS = 256; const MAX_SYMBOL_ID_CHARS = 512; +const MAX_GROUNDING_SYMBOLS = 50; const MAX_SEARCH_RESULTS = 500; const MAX_RELATION_RESULTS = 500; const MAX_SIGNATURE_CHARS = 4 * 1024; @@ -154,6 +155,8 @@ export interface RepositoryGraphGroundingSnapshot { /** Exact immutable graph snapshot revision, for composite Wiki cursors. */ readonly revision: string; getNode(nodeId: string): RepositoryGraphGroundedNode | null; + /** Up to 50 direct symbols, in request order without duplicates or source bodies. */ + getSymbols(nodeIds: readonly string[]): readonly CodeSymbol[]; getFingerprint(nodeId: string): string | null; reconcile(nodeId: string, committedFingerprint: string): Resolution | null; getBaselineSource(subject: GroundingSubject, nodeId: string): GroundingBaseline | null; @@ -412,6 +415,23 @@ export class RepositoryGraphPort implements GraphPort { }; const snapshot: RepositoryGraphGroundingSnapshot = { revision: context.revision, + getSymbols(nodeIds) { + assertActive(); + if (!Array.isArray(nodeIds) || nodeIds.length > MAX_GROUNDING_SYMBOLS) { + throw invalid("A grounding symbol request accepts at most 50 node IDs."); + } + const ids = [...new Set(Array.from(nodeIds, validateSymbolId))]; + try { + return ids.flatMap((id) => { + const node = context.session.graph.getNode(id); + // Graph point reads also follow aliases. Only the requested + // declaration belongs in this direct-symbol projection. + return node?.id === id ? [projectNode(node)] : []; + }); + } catch { + throw interruptedRead("The graph grounding snapshot could not read symbols safely."); + } + }, getNode(nodeId) { assertActive(); try { diff --git a/src/hub/__tests__/services.test.ts b/src/hub/__tests__/services.test.ts index edeba47e..066455c2 100644 --- a/src/hub/__tests__/services.test.ts +++ b/src/hub/__tests__/services.test.ts @@ -14,6 +14,8 @@ import { InboxProposalListResponseSchema, SpecDetailResponseSchema, SpecListResponseSchema, + WikiGraphResponseSchema, + WikiGroundedCodeResponseSchema, type HubJobSnapshot, } from "@mex/hub-contracts"; import { OverviewResponseSchema } from "@mex/hub-contracts/overview"; @@ -1337,6 +1339,148 @@ The governed authoring test keeps one canonical entity available to the exact-re expect(JSON.stringify(detail)).not.toContain("session-private"); }); + it("truncates metadata-rich Context nodes to one MiB without retaining dangling relations", async () => { + const nodes = Array.from({ length: 100 }, (_, index) => ({ + ...wikiSummary(`mx_${String(index + 1).padStart(26, "0")}`, "pattern", "界".repeat(170)), + summary: "🧭".repeat(512), + topics: Array.from({ length: 50 }, (_, topic) => `mx_${String(topic + 1_000).padStart(26, "0")}`), + sourceTypes: Array.from({ length: 50 }, (_, type) => `source-${type}-`.padEnd(128, "x")), + location: { path: `.mex/context/${"nested/".repeat(110)}entry.md`, startLine: 1, endLine: 12 }, + })); + const wiki = { + ...wikiWithStatus("fresh"), + graphOverview: async () => ({ + indexedRevision: "f".repeat(64), + observedAt: NOW.toISOString(), + nodes, + relations: [ + { type: "related_to", source: { id: nodes[0]!.ref.id, kind: "pattern" }, target: { id: nodes[99]!.ref.id, kind: "pattern" }, note: "Omitted target" }, + { type: "related_to", source: { id: nodes[0]!.ref.id, kind: "pattern" }, target: { id: nodes[1]!.ref.id, kind: "pattern" }, note: "Included target" }, + ], + coverage: { nodeLimit: 100 as const, relationLimit: 500 as const, nodesTruncated: false, relationsTruncated: false }, + }), + } satisfies HubWikiReadService; + const services = createLocalHubReadServices({ + projectRoot, scaffoldId: "scaffold-local", git, wiki, + jobs: { list: () => ({ items: [] }) }, now: () => new Date(NOW), + }); + + const result = await services.wikiGraph!(); + expect(WikiGraphResponseSchema.safeParse(result).success).toBe(true); + expect(Buffer.byteLength(JSON.stringify(result), "utf8")).toBeLessThanOrEqual(HUB_LIMITS.maxJsonResponseBytes); + expect(result.nodes.length).toBeGreaterThan(1); + expect(result.nodes.length).toBeLessThan(nodes.length); + expect(result.coverage).toMatchObject({ nodesTruncated: true, relationsTruncated: true }); + expect(result.relations).toHaveLength(1); + expect(result.relations[0]!.note).toBe("Included target"); + const included = new Set(result.nodes.map((node) => node.id)); + expect(result.relations.every((relation) => included.has(relation.source.id) && included.has(relation.target.id))).toBe(true); + }); + + it("truncates metadata-rich Context relations to one MiB while preserving the complete node set", async () => { + const nodes = Array.from({ length: 100 }, (_, index) => ( + wikiSummary(`mx_${String(index + 1).padStart(26, "0")}`, "pattern", "界".repeat(170)) + )); + const relations = Array.from({ length: 500 }, (_, index) => ({ + type: "related_to", + source: nodes[index % nodes.length]!.ref, + target: nodes[(index + 1 + Math.floor(index / nodes.length)) % nodes.length]!.ref, + note: "🧭".repeat(512), + metadata: { privateMarker: "unprojected-edge-metadata" }, + })); + const wiki = { + ...wikiWithStatus("fresh"), + graphOverview: async () => ({ + indexedRevision: "f".repeat(64), observedAt: NOW.toISOString(), nodes, relations, + coverage: { nodeLimit: 100 as const, relationLimit: 500 as const, nodesTruncated: false, relationsTruncated: false }, + }), + } satisfies HubWikiReadService; + const services = createLocalHubReadServices({ + projectRoot, scaffoldId: "scaffold-local", git, wiki, + jobs: { list: () => ({ items: [] }) }, now: () => new Date(NOW), + }); + + const result = await services.wikiGraph!(); + expect(WikiGraphResponseSchema.safeParse(result).success).toBe(true); + const serialized = JSON.stringify(result); + expect(Buffer.byteLength(serialized, "utf8")).toBeLessThanOrEqual(HUB_LIMITS.maxJsonResponseBytes); + expect(result.nodes.map((node) => node.id)).toEqual(nodes.map((node) => node.ref.id)); + expect(result.relations.length).toBeGreaterThan(0); + expect(result.relations.length).toBeLessThan(relations.length); + expect(result.coverage).toMatchObject({ nodesTruncated: false, relationsTruncated: true }); + expect(serialized).not.toContain("unprojected-edge-metadata"); + const included = new Set(result.nodes.map((node) => node.id)); + expect(result.relations.every((relation) => included.has(relation.source.id) && included.has(relation.target.id))).toBe(true); + }); + + it("projects compact grounded code through an allowlist and preserves absent symbols", async () => { + const entityId = "mx_01ARZ3NDEKTSV4RRFFQ69G5FA1"; + const symbol = { + ref: { kind: "symbol" as const, symbolId: "function:router", fingerprint: "private-fingerprint" }, + symbolKind: "function", name: "router", qualifiedName: "hub.router", language: "typescript", + path: "src/router.ts", startLine: 3, endLine: 7, signature: "界".repeat(1_000), + content: "private-source-body", bodyHash: "private-body-hash", docstring: "private-docstring", + }; + const readGroundedCode = vi.fn(async (id: string) => ({ + indexedRevision: "f".repeat(64), observedAt: NOW.toISOString(), entityId: id, + graphRevision: "c".repeat(64), + groundings: [ + { + requestedNode: "function:old-router", resolvedNode: "function:router", health: "changed" as const, + symbol, reason: "private-grounding-reason", fingerprint: "private-fingerprint", + }, + { requestedNode: "function:missing", resolvedNode: null, health: "missing" as const, symbol: null }, + ], + truncated: true, + privateMetadata: "private-top-level-metadata", + })); + const wiki = { ...wikiWithStatus("fresh"), readGroundedCode } satisfies HubWikiReadService; + const services = createLocalHubReadServices({ + projectRoot, scaffoldId: "scaffold-local", git, wiki, + jobs: { list: () => ({ items: [] }) }, now: () => new Date(NOW), + }); + + const result = await services.wikiGroundedCode!(entityId); + expect(readGroundedCode).toHaveBeenCalledExactlyOnceWith(entityId); + expect(WikiGroundedCodeResponseSchema.safeParse(result).success).toBe(true); + expect(result).toMatchObject({ + entityId, graphRevision: "c".repeat(64), truncated: true, + groundings: [ + { + requestedNode: "function:old-router", resolvedNode: "function:router", health: "changed", + symbol: { id: "function:router", name: "router", path: "src/router.ts", startLine: 3, endLine: 7 }, + }, + { requestedNode: "function:missing", resolvedNode: null, health: "missing", symbol: null }, + ], + }); + expect(Buffer.byteLength(result.groundings[0]!.symbol!.signature!, "utf8")).toBeLessThanOrEqual(2_048); + expect(JSON.stringify(result)).not.toContain("private-"); + }); + + it("keeps grounded code unavailable without inventing a Graph revision or symbol", async () => { + const entityId = "mx_01ARZ3NDEKTSV4RRFFQ69G5FA1"; + const wiki = { + ...wikiWithStatus("fresh"), + readGroundedCode: async () => ({ + indexedRevision: "f".repeat(64), observedAt: NOW.toISOString(), entityId, + graphRevision: null, + groundings: [{ requestedNode: "function:router", resolvedNode: null, health: "unverified" as const, symbol: null }], + truncated: false, + }), + } satisfies HubWikiReadService; + const services = createLocalHubReadServices({ + projectRoot, scaffoldId: "scaffold-local", git, wiki, + jobs: { list: () => ({ items: [] }) }, now: () => new Date(NOW), + }); + + const result = await services.wikiGroundedCode!(entityId); + expect(WikiGroundedCodeResponseSchema.safeParse(result).success).toBe(true); + expect(result).toMatchObject({ + graphRevision: null, + groundings: [{ requestedNode: "function:router", resolvedNode: null, health: "unverified", symbol: null }], + }); + }); + it("projects real bounded Wiki browse, detail, relations, search, Code links, and health", async () => { const entity = "mx_01K4FAM7W8N9R3T5Y6Q2ZBCHJD"; const target = "mx_01K4FAM7W8N9R3T5Y6Q2ZBCHJE"; diff --git a/src/hub/app.ts b/src/hub/app.ts index 6228b443..031acf14 100644 --- a/src/hub/app.ts +++ b/src/hub/app.ts @@ -70,6 +70,8 @@ import { WikiEntityListResponseSchema, WikiRelationsRequestSchema, WikiRelationsResponseSchema, + WikiGraphResponseSchema, + WikiGroundedCodeResponseSchema, type HealthResponse, type CodeWorkspaceRequest, type CodeWorkspaceResponse, @@ -126,6 +128,8 @@ import { type WikiEntityListResponse, type WikiRelationsRequest, type WikiRelationsResponse, + type WikiGraphResponse, + type WikiGroundedCodeResponse, } from "@mex/hub-contracts"; import { OverviewResponseSchema } from "@mex/hub-contracts/overview"; import { Hono, type Context } from "hono"; @@ -238,6 +242,8 @@ export interface HubReadServices { wikiEntities?( request: WikiEntityListRequest, ): Promise | WikiEntityListResponse; + wikiGraph?(): Promise | WikiGraphResponse; + wikiGroundedCode?(entityId: string): Promise | WikiGroundedCodeResponse; wikiEntity?( entityId: string, ): Promise | WikiEntityDetailResponse; @@ -640,6 +646,19 @@ export function createHubApp(options: CreateHubAppOptions): Hono ); }); + app.get("/api/v1/wiki/graph", async (context) => { + if (!options.services.wikiGraph) throw unavailable("Context graph reads are not connected in this build."); + graphInput(() => readStrictQuery(context.req.raw, [])); + return resourceResponse(WikiGraphResponseSchema, await options.services.wikiGraph()); + }); + + app.get("/api/v1/wiki/entities/:id/code", async (context) => { + if (!options.services.wikiGroundedCode) throw unavailable("Context code reads are not connected in this build."); + const entityId = graphInput(() => parseInput(WikiEntityIdSchema, context.req.param("id"))); + graphInput(() => readStrictQuery(context.req.raw, [])); + return resourceResponse(WikiGroundedCodeResponseSchema, await options.services.wikiGroundedCode(entityId)); + }); + app.get("/api/v1/wiki/entities", async (context) => { if (!options.services.wikiEntities) throw unavailable("Wiki reads are not connected in this build."); const request = graphInput(() => parseInput( diff --git a/src/hub/services.ts b/src/hub/services.ts index 8255a24b..b8096d63 100644 --- a/src/hub/services.ts +++ b/src/hub/services.ts @@ -78,6 +78,8 @@ import { type WikiEntityListResponse, type WikiEntitySummary as HubWikiEntitySummary, type WikiGrounding as HubWikiGrounding, + type WikiGraphResponse, + type WikiGroundedCodeResponse, type WikiHealthDetails, type WikiRelation as HubWikiRelation, type WikiRelationsRequest, @@ -188,6 +190,8 @@ import type { RepositoryKnowledgeWorkspaceRequest, RepositoryWikiListBundle, RepositoryWikiSearchBundle, + RepositoryWikiGraphOverview, + RepositoryWikiGroundedCode, } from "../wiki/application-adapter.js"; import { TEAM_READABLE_ENTITY_TYPES, @@ -215,6 +219,8 @@ export interface HubWikiReadService { searchBundle(request: WikiQueryRequest): Promise; readKnowledgeWorkspace(request: RepositoryKnowledgeWorkspaceRequest): Promise; knowledgeForCode(request: RepositoryCodeKnowledgeRequest): Promise; + graphOverview?(): Promise; + readGroundedCode?(entityId: string): Promise; } /** Exact internal C0 application facade used by the private Hub. */ @@ -837,6 +843,29 @@ export function createLocalHubReadServices( return readCodeWorkspace(graph, symbolId, request); }, + async wikiGraph(): Promise { + const connected = requireWiki(wiki); + if (!connected.graphOverview) throw unavailableWikiGraph(); + return projectWikiGraph(await connected.graphOverview()); + }, + + async wikiGroundedCode(entityId: string): Promise { + const connected = requireWiki(wiki); + if (!connected.readGroundedCode) throw unavailableWikiGraph(); + const result = await connected.readGroundedCode(entityId); + return { + indexedRevision: result.indexedRevision, observedAt: result.observedAt, + entityId: result.entityId, graphRevision: result.graphRevision, + groundings: result.groundings.map((grounding) => ({ + requestedNode: boundedWikiText(grounding.requestedNode, 512, ""), + resolvedNode: grounding.resolvedNode === null ? null : boundedWikiText(grounding.resolvedNode, 512, ""), + health: grounding.health, + symbol: grounding.symbol === null ? null : projectGraphSymbol(grounding.symbol), + })), + truncated: result.truncated, + }; + }, + async wikiEntities(request: WikiEntityListRequest): Promise { const connected = requireWiki(wiki); if (request.kind !== undefined && isTeamReadableEntityKind(request.kind)) { @@ -1220,6 +1249,44 @@ function projectGraphImpact(impact: GraphImpactResult): CodeWorkspaceResponse["t }; } +function unavailableWikiGraph(): HubHttpError { + return new HubHttpError(503, "CAPABILITY_UNAVAILABLE", "Capability unavailable", "Context graph reads are not connected in this build."); +} + +function projectWikiGraph(bundle: RepositoryWikiGraphOverview): WikiGraphResponse { + const result: WikiGraphResponse = { + indexedRevision: bundle.indexedRevision, observedAt: bundle.observedAt, + nodes: [], relations: [], coverage: { ...bundle.coverage }, + }; + let bytes = Buffer.byteLength(JSON.stringify(result), "utf8"); + for (const entity of bundle.nodes) { + const node = projectWikiSummary(entity); + const cost = Buffer.byteLength(JSON.stringify(node), "utf8") + (result.nodes.length > 0 ? 1 : 0); + if (bytes + cost > HUB_LIMITS.maxJsonResponseBytes) { + result.coverage.nodesTruncated = true; + break; + } + bytes += cost; + result.nodes.push(node); + } + const included = new Set(result.nodes.map((node) => node.id)); + for (const value of bundle.relations) { + if (!included.has(value.source.id) || !included.has(value.target.id)) { + result.coverage.relationsTruncated = true; + continue; + } + const relation = projectWikiRelation(value); + const cost = Buffer.byteLength(JSON.stringify(relation), "utf8") + (result.relations.length > 0 ? 1 : 0); + if (bytes + cost > HUB_LIMITS.maxJsonResponseBytes) { + result.coverage.relationsTruncated = true; + break; + } + bytes += cost; + result.relations.push(relation); + } + return result; +} + function projectWikiSummary(entity: WikiEntitySummary): HubWikiEntitySummary { if (!isCanonicalRepoPath(entity.location.path)) throw invalidWikiProjection(); const topics = entity.topics.slice(0, 50); diff --git a/src/wiki/__tests__/context-graph.test.ts b/src/wiki/__tests__/context-graph.test.ts new file mode 100644 index 00000000..e27266b6 --- /dev/null +++ b/src/wiki/__tests__/context-graph.test.ts @@ -0,0 +1,151 @@ +import { mkdtempSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { createRepositoryWikiPort, type RepositoryWikiGroundingSnapshot } from "../application-adapter.js"; +import { withWikiContractReadSessionAsync } from "../query/contract-session.js"; +import { MexPortError } from "../../team/contracts/shared.js"; + +const roots: string[] = []; +const id = (index: number) => `mx_${String(index).padStart(26, "0")}`; +const NODE = "function:1111111111111111"; +const FINGERPRINT = "mh:4:11111111"; +afterEach(() => { while (roots.length) rmSync(roots.pop()!, { recursive: true, force: true }); }); + +function fixture(count = 32, dense = false, grounded = false) { + const root = mkdtempSync(join(tmpdir(), "mex-context-graph-")); + roots.push(root); + const scaffold = join(root, ".mex"); + mkdirSync(join(scaffold, "context"), { recursive: true }); + const path = join(scaffold, "context", "units.md"); + const metadata = (index: number) => { + const targets = dense ? Array.from({ length: count }, (_, i) => i).filter((i) => i !== index) + : index === 0 ? [1] : []; + return `id: ${id(index)}\ntype: ${index === 0 ? "architecture" : "component"}\nstatus: ${index === count - 1 ? "archived" : "promoted"}\nrevision: 1\n` + + (targets.length ? `relations:\n${targets.map((target) => ` - type: related_to\n target: ${id(target)}\n note: Recorded connection ${index} to ${target}\n`).join("")}` : "") + + (grounded && index === 0 ? `grounds_to:\n - node: ${NODE}\n fingerprint: ${FINGERPRINT}\n` : ""); + }; + writeFileSync(path, `---\nmex:\n${metadata(0).split("\n").filter(Boolean).map((line) => ` ${line}\n`).join("")}---\n# Unit 000\n\nA document entity.\n\n` + + Array.from({ length: count - 1 }, (_, i) => i + 1).map((index) => ( + `\n## Unit ${String(index).padStart(3, "0")}\n\nA separately addressable section.\n\n` + )).join("")); + return { root, scaffold, path }; +} + +function snapshot() { + return { + revision: "b".repeat(64), + getNode: (node: string) => node === NODE ? { id: NODE, bodyHash: "c".repeat(64), filePath: "src/queue.ts", startLine: 1, endLine: 4 } : null, + getFingerprint: (node: string) => node === NODE ? FINGERPRINT : null, + reconcile: () => null, getBaselineSource: () => null, + getSymbols: vi.fn((nodes: readonly string[]) => nodes.includes(NODE) ? [{ + ref: { kind: "symbol" as const, symbolId: NODE }, symbolKind: "function", name: "queue", qualifiedName: "queue", language: "typescript", + path: "src/queue.ts", startLine: 1, endLine: 4, signature: "queue(): void", + }] : []), + } satisfies RepositoryWikiGroundingSnapshot; +} + +describe("Context graph repository reads", () => { + it("includes every document and disconnected section, including archived units, and excludes Team kinds", async () => { + const target = fixture(); + mkdirSync(join(target.scaffold, "workstreams")); + writeFileSync(join(target.scaffold, "workstreams", "team.md"), `\n## Team work\n\nA separate workbench.\n`); + const port = createRepositoryWikiPort(target.root); + await port.rebuildIndex(); + const index = join(target.scaffold, "wiki.db"); + const before = { bytes: readFileSync(index), mtime: statSync(index).mtimeMs, entries: readdirSync(target.scaffold) }; + const graph = await port.graphOverview(); + expect(graph.nodes).toHaveLength(32); + expect(graph.nodes.map((node) => node.ref.id)).toEqual(Array.from({ length: 32 }, (_, index) => id(index))); + expect(graph.nodes.at(-1)?.lifecycleState).toBe("archived"); + expect(graph.relations).toMatchObject([{ type: "related_to", source: { id: id(0) }, target: { id: id(1) }, note: "Recorded connection 0 to 1" }]); + expect(graph.coverage).toEqual({ nodeLimit: 100, relationLimit: 500, nodesTruncated: false, relationsTruncated: false }); + expect(graph.indexedRevision).toBe((await port.readKnowledgeWorkspace({ entityId: id(0) })).indexedRevision); + expect({ bytes: readFileSync(index), mtime: statSync(index).mtimeMs, entries: readdirSync(target.scaffold) }).toEqual(before); + }); + + it("caps the node set and relationships independently without dangling displayed endpoints", async () => { + const large = fixture(101); + const largePort = createRepositoryWikiPort(large.root); + await largePort.rebuildIndex(); + const graph = await largePort.graphOverview(); + expect(graph.nodes).toHaveLength(100); + expect(graph.coverage.nodesTruncated).toBe(true); + const dense = fixture(26, true); + const densePort = createRepositoryWikiPort(dense.root); + await densePort.rebuildIndex(); + const denseGraph = await densePort.graphOverview(); + expect(denseGraph.relations).toHaveLength(500); + expect(denseGraph.coverage).toMatchObject({ nodesTruncated: false, relationsTruncated: true }); + const ids = new Set(denseGraph.nodes.map((node) => node.ref.id)); + expect(denseGraph.relations.every((edge) => ids.has(edge.source.id) && ids.has(edge.target.id))).toBe(true); + }); + + it("rejects missing, stale, and mid-read changed Wiki snapshots without repair", async () => { + const target = fixture(3); + const port = createRepositoryWikiPort(target.root); + await expect(port.graphOverview()).rejects.toMatchObject({ problem: { code: "INDEX_MISSING" } }); + await port.rebuildIndex(); + const index = join(target.scaffold, "wiki.db"); + const before = readFileSync(index); + const racing = createRepositoryWikiPort(target.root, { __internal: { + readAsync: (options, callback) => withWikiContractReadSessionAsync(options, async (session) => { + const result = await callback(session); + writeFileSync(target.path, readFileSync(target.path, "utf8") + "\nChanged during read.\n"); + return result; + }), + } }); + await expect(racing.graphOverview()).rejects.toMatchObject({ problem: { code: "REVISION_CONFLICT" } }); + await expect(port.graphOverview()).rejects.toMatchObject({ problem: { code: "INDEX_STALE" } }); + await expect(port.readGroundedCode(id(0))).rejects.toMatchObject({ problem: { code: "INDEX_STALE" } }); + expect(readFileSync(index)).toEqual(before); + }); + + it("reads compact symbols and grounding health through one shared Graph observation", async () => { + const target = fixture(3, false, true); + await createRepositoryWikiPort(target.root).rebuildIndex(); + const graph = snapshot(); + let calls = 0; + const port = createRepositoryWikiPort(target.root, { groundingBridge: { + async withFreshGroundingSnapshot(callback) { calls += 1; return callback(graph); }, + } }); + const result = await port.readGroundedCode(id(0)); + expect(calls).toBe(1); + expect(graph.getSymbols).toHaveBeenCalledExactlyOnceWith([NODE]); + expect(result).toMatchObject({ entityId: id(0), graphRevision: graph.revision, truncated: false, + groundings: [{ requestedNode: NODE, resolvedNode: NODE, health: "fresh", symbol: { ref: { symbolId: NODE }, name: "queue" } }], + }); + expect(JSON.stringify(result)).not.toContain("fingerprint"); + expect(JSON.stringify(result)).not.toContain("bodyHash"); + expect((await port.readGroundedCode(id(1))).groundings).toEqual([]); + }); + + it("discards Graph results after final freshness failure and keeps canonical groundings unverified", async () => { + const target = fixture(3, false, true); + await createRepositoryWikiPort(target.root).rebuildIndex(); + const port = createRepositoryWikiPort(target.root, { groundingBridge: { + async withFreshGroundingSnapshot(callback) { + await callback(snapshot()); + throw new MexPortError({ code: "REVISION_CONFLICT", status: 409, title: "Graph changed", detail: "Final Graph observation changed." }); + }, + } }); + await expect(port.readGroundedCode(id(0))).resolves.toMatchObject({ + graphRevision: null, groundings: [{ requestedNode: NODE, resolvedNode: null, health: "unverified", symbol: null }], + }); + await expect(port.readGroundedCode(id(99))).rejects.toMatchObject({ problem: { code: "NOT_FOUND" } }); + }); + + it("bounds canonical grounding entries even when code is unavailable", async () => { + const target = fixture(3); + const source = readFileSync(target.path, "utf8").replace(" revision: 1\n", " revision: 1\n grounds_to:\n" + + Array.from({ length: 51 }, (_, index) => ` - node: function:${String(index).padStart(16, "0")}\n fingerprint: ${FINGERPRINT}\n`).join("")); + writeFileSync(target.path, source); + const port = createRepositoryWikiPort(target.root); + await port.rebuildIndex(); + const result = await port.readGroundedCode(id(0)); + expect(result.groundings).toHaveLength(50); + expect(result.truncated).toBe(true); + expect(result.graphRevision).toBeNull(); + expect(result.groundings.every((grounding) => grounding.health === "unverified" && grounding.symbol === null)).toBe(true); + }); +}); diff --git a/src/wiki/application-adapter.ts b/src/wiki/application-adapter.ts index bed23286..91446fee 100644 --- a/src/wiki/application-adapter.ts +++ b/src/wiki/application-adapter.ts @@ -137,11 +137,15 @@ import { type WikiValidationRequest, } from "../team/contracts/wiki.js"; import { isRepoRelativePath, MexPortError } from "../team/contracts/shared.js"; +import type { CodeSymbol } from "../team/contracts/graph.js"; +import { WIKI_ENTITY_TYPES } from "./model/entity.js"; const MAX_DIAGNOSTICS = 100; const MAX_COUNTED_ENTITIES = 10_000; const MAX_COUNTED_RELATIONS = 100_000; const MAX_PRIVATE_PAGE = 50; +const MAX_CONTEXT_NODES = 100; +const MAX_CONTEXT_RELATIONS = 500; const MAX_CODE_LOOKUP_NODES = 50; const MAX_CURSOR_BYTES = 4 * 1024; const MAX_OPAQUE_PLANS = 128; @@ -193,6 +197,33 @@ export interface RepositoryWikiListBundle { readonly results: WikiPage; } +export interface RepositoryWikiGraphOverview { + readonly indexedRevision: Revision; + readonly observedAt: string; + readonly nodes: readonly WikiEntitySummary[]; + readonly relations: readonly WikiRelation[]; + readonly coverage: { + readonly nodeLimit: 100; + readonly relationLimit: 500; + readonly nodesTruncated: boolean; + readonly relationsTruncated: boolean; + }; +} + +export interface RepositoryWikiGroundedCode { + readonly indexedRevision: Revision; + readonly observedAt: string; + readonly entityId: EntityId; + readonly graphRevision: string | null; + readonly groundings: readonly { + readonly requestedNode: string; + readonly resolvedNode: string | null; + readonly health: GroundingHealth; + readonly symbol: CodeSymbol | null; + }[]; + readonly truncated: boolean; +} + export type RepositoryKnowledgeSelection = | { readonly kind: "overview" } | { readonly kind: "relations"; readonly results: WikiPage } @@ -348,6 +379,8 @@ export interface RepositoryWikiGroundingBridge { export type RepositoryWikiGroundingSnapshot = GroundingGraph & { /** Exact Graph snapshot revision used to bind current-projection cursors. */ readonly revision: string; + /** Optional compact symbol projection, bound to this same revocable snapshot. */ + getSymbols?(nodeIds: readonly string[]): readonly CodeSymbol[]; }; export interface RepositoryWikiPreparedPublication { @@ -450,6 +483,88 @@ export class RepositoryWikiPort implements WikiPort< })); } + /** All visible Context units and their authored edges from one immutable read. */ + async graphOverview(): Promise { + return this.#readCurrent((session, graph) => { + const status = session.status(); + if (status.state !== "fresh") throw indexError(status); + const page = session.list({ kinds: WIKI_ENTITY_TYPES, includeArchived: true, limit: MAX_CONTEXT_NODES }); + const nodes = page.items.map((entity) => this.#projectCurrentSummary(session, graph, entity)); + const included = new Set(nodes.map((entity) => entity.ref.id)); + const relations: WikiRelation[] = []; + let relationsTruncated = false; + // Each source has at most 200 queryable relationships. Two ordinary pages + // per source keep the scan bounded even when most targets are excluded. + sources: for (const node of nodes) { + let cursor: string | undefined; + for (let pageIndex = 0; pageIndex < 2; pageIndex += 1) { + const edges = session.relations({ + entityId: node.ref.id, direction: "outgoing", includeArchived: true, + limit: 100, ...(cursor === undefined ? {} : { cursor }), + }); + for (const hit of edges.items) { + if (!included.has(hit.relation.target.id)) { + if (hit.entity !== null && (WIKI_ENTITY_TYPES as readonly string[]).includes(hit.entity.type)) { + relationsTruncated = true; + } + continue; + } + if (relations.length === MAX_CONTEXT_RELATIONS) { + relationsTruncated = true; + break sources; + } + relations.push(projectRelation(hit.relation)); + } + cursor = edges.nextCursor ?? undefined; + if (cursor === undefined) { + if (edges.truncated) relationsTruncated = true; + break; + } + if (pageIndex === 1) relationsTruncated = true; + } + } + return { + indexedRevision: session.indexedRevision, + observedAt: stableObservationTime(session), nodes, relations, + coverage: { + nodeLimit: MAX_CONTEXT_NODES, relationLimit: MAX_CONTEXT_RELATIONS, + nodesTruncated: page.truncated, relationsTruncated, + }, + }; + }); + } + + /** Only direct, resolved grounding symbols; never fetch source bodies or traverse code. */ + async readGroundedCode(entityId: EntityId): Promise { + return this.#readCurrent((session, graph) => { + const status = session.status(); + if (status.state !== "fresh") throw indexError(status); + const entity = session.get(entityId); + if (entity === null || !(WIKI_ENTITY_TYPES as readonly string[]).includes(entity.type)) { + throw portError("NOT_FOUND", 404, "Wiki entity not found", "The requested Context entity does not exist."); + } + const projected = projectGroundings(entity.groundings.slice(0, MAX_CODE_LOOKUP_NODES), stableObservationTime(session), graph); + const groundings = projected.flatMap((grounding) => grounding.state === "ungrounded" ? [] : [{ + requestedNode: grounding.requestedNode, + resolvedNode: grounding.state === "fresh" || grounding.state === "stale" + ? grounding.resolvedNode ?? null : null, + health: grounding.health, + }]); + const symbols = graph?.getSymbols?.(groundings.flatMap((grounding) => ( + grounding.resolvedNode === null ? [] : [grounding.resolvedNode] + ))) ?? []; + const byId = new Map(symbols.map((symbol) => [symbol.ref.symbolId, symbol])); + return { + indexedRevision: session.indexedRevision, observedAt: stableObservationTime(session), entityId, + graphRevision: graph?.getSymbols === undefined ? null : graph.revision, + groundings: groundings.map((grounding) => ({ + ...grounding, symbol: grounding.resolvedNode === null ? null : byId.get(grounding.resolvedNode) ?? null, + })), + truncated: entity.groundings.length > MAX_CODE_LOOKUP_NODES, + }; + }); + } + /** * Package-private exact refresh discovery. Added, modified, and deleted * canonical paths are compared inside one immutable Wiki read handshake. diff --git a/test/hub-e2e/__screenshots__/darwin/hub-home.png b/test/hub-e2e/__screenshots__/darwin/hub-home.png index b89b4b572988c4ecd8cd28fbfbde43731669fe9b..96b76e76df78adf69ce8f648233d1f1a2e35aa5c 100644 GIT binary patch literal 235427 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\lil#ocj ze9}g5YL!ZR6S>kY>1KS1Tb@89tSUA2G1H9LcLPTbqgvPXs1Xj6*&V$d9ea#sR_(9M z(qT$_dw{P~6iVz?`TJji{^#38krfY6Wo-zD z8i>QN#HQ@=KKs&+CRF+qZr3Ik8dKd4j^MPDc~cVITBhmy))6~nVgqmeoj{YQU0xbx zX}$H#MK}TqN0SC_t>g+zwQzY1fmE-1eep8|HdZR2tC*OBUkuOHz1!SzL&_u$Aya*=W;Faxy`As;b~fkh=L(+} z1--`nc?oGTf&*r!S}&aLS5PGq^}hF>{>8ZeTM^Ib^Fys$C*1USPoyOy?d{<0L2*`E zLYTwPIcu_$bvXWL7`Gm(E)lu;^RB zxAyj5#TFgyvP8^n9zD;>y|+wb#18w^EHpD{3w&biJaWXQnztO?ZqbQdW1mbmIQZWb zG;*MQ;q7!AGYq8y4>V;&5~SXlK#)oP(N%T1Z#&f5c| z+`pKr57&nuSmV;)%Uu3@vHm&r8AhEFitU*TZ>2@zCrp-0W3L{dDc*VcO7iUYs&z1xD zL_@~MSSkCY0Es~&-)u5ioF4H{jQpL>;?`5al*S;*_L`f&rIzl&iV`GVGgf79JP_Df zjwJc|H=tXYmqt3zxce26G^L=)7~?@io2!p*=eu_-mLruVb(`#q)(-`V&BApSeO7ng zS);AxJy#vX2OjZvRv*SNFuxMtJKt(Ihf=xwP0E4s!5vYODr*1OvdkePJc^1f3c2Hh z{r!2&xgO8O9V8u{3i`|fXe8XWP7H|7u7WRdxsEqdcG^}gf9G|q`e4>NNC4TFwcw)O!It3T~5Yx`xxv*f5h$_u>uc^lf^O2>%xW7FpULycumyq1#76^MTUQYrq5I4SX9jg$26+86x}D-x=+c2f3bJDnOL zamsdWcgVvJcYGGStVNf-!OS*(m3X$h(in1X+(15a8i$KHxN4RV}Y3qf4Fo3tl?}exy1ux?C~1isZRMIYuzo~SkVo5sr2iKOxYv9A;4KA zMca7|AMq{#;OrAG?Lg9ib@~o>Kx|Jy+Dz*s>>>eGNNlD7&5P(ME?(YnObO5jbsWI_ zvk!23{*rB;EEP)-m^#=Ca4B(8@*Mw98u`+_ylvVLPgOUe(?BP7lz(WqhD4zP=)^OH z_)UgMtl7IxTnXKG2;dpP_>f$Hw(AS16zn^~%VmeRj(quYzT+>Mu4^i^c1T%CiATXD zwzPB#L+riT+EM zP3AbfB9XQ3KywJ>BmHDa&Nrl`jU#Tl?x{lS*a7lwS&F|55&uWF$+A}nUBwA3 z4g+$GSqytU=AfU;{Fz*Kuo_NlOO(eo7*s0|17tz$tHPmZ{s>(Faw~D)+r!HLA0bXR zRp%CWKTXIPU~vG(kG<8mUW%Dsk)E2JEg!nr@o#cY7NxD&^Aa#S!{hp&`eiI|n3wKFB0X*dOa(C>apw{g<6W7gNBHNkW=}?)^VN7<+c`y7+=FyMFxmQEP4H0kp_nvJO=bBO|w{ z3Cu02*4Cc6zT=Vx2KP3y}`A7pY!RU$#xeWxLo*kqc?b&)g&diunOZgNI$F-#u=S&3lm-X~!-)l0 zmmgpDn#X8TILBvaAAs1TQr)`)*-XeYnVpyj0No4n2}@|m4=v;H)#WG0d zu3ep1<@njyMAu|5rlc4>v<8cZo19(BZW1URN?X$s!PtOb2A#gczU&OD8>*J@@RM_! z^{J_rpmov{Gl5$3z_fQB(n7qoe?u65yFvpt*T1$^^}@?nui|ufdG?T7H=!+U8C+Oe zGPs9;sRE^;)>bi1&BNm5L^9hZIOLo}YnE2$gG1$4v^c>=EoKx4;ivc3SrVVn`uND? zWQpa6#Q#HCM{22_@g97%ms77P!l>BbbY5)td6BiL|470L7_O6?WHI~CceWJqzp-QM ze_LK{PQg^i0JRPzW5+jA^Ur2JDydjLY)MlE5mKC zs;XK_efWR&2oUL$uqqqVUF5&D^@O3Dn;Vk!aUJULp+j$jn#Qo6c7mLOf)HpIY~mR; zlpNQGVjhbIpg+Lh_AspBKMhJd`Q+(SNPeqy&!ci=a3BawQ6JBwRRq*{MTqt{m`gBM z0l&;eh_&#?CR&lqlwLxc8ZSXcjN{03Rg;&uBEGU>%1#CeL;Q;=4e>9H0|N&GlVtz? z6xl>PK2N47#NeXIh+?i$g5IXG(&;%5u0W;_{HsTxhWMg4z7Gn`A7$>r=gCtV&tb~YP)U)*%4G3z3Oie6-nR?mV zoB1gjlz;aiuBkyLz#+VJON+?A*N>^#{_tU5Q&zAF8Lj`bI85RlaWnt>C;R`V8T^m* zUt$)~vWB5pg^rz2@CSEL*2Y(#`U})qE*qDeX-SBW zCHecybzi)16ih*WEK~UT?Y%E*j?kE{V@$zSlVW1{KyCMbf~o8*q6R+K|H1oh(Lk!Q zMOd6b=RAJpe9JaP)!v?kr+Ob{B}A!X=HD^1v0?kf#ogyOeOc(Zun$49aubV4Vxprf zb%@KEsfNyvZXz4Q6EY^kFe>3}Wa1~siW4v>yrr+O7dsFGF#hL}U8xPWNz4pX-w`O- zyj){pWX;5EaK81;Wvw(_tUdw*q$waEAR;27sJJL&8P+)CK+PUUfyD|T?2gGHQ?6qPi}L9{`YY>-vCL0 z<^c@>^j_x=A1`=Uc=jZ0rCErp)o@Vkp;9{)MM@#Ba3%6K0mvsmNf5sxdnEMF?*M5x z{6*r)5O4r+7ep32%ivskeE)ur)*&D<56$u$&dX>bwG)aFoDazqqmt5G->w0IfDXNC z9oY`*YHA%%fFR&QMnCGM+H=2-rh5i+Y$c$SYh=; z$sq*IXmA`6F#WIbuYVA@G(ZE9c47f{2CV@DCP^u1LqPxnixSt2OYdLAJ?wlDno9yl ze?&5-z-1GIj5PdmstT8$qCNfFFSIoyV{P^KZ=u6z18E=er^nX_)s6!i?P_i&(`8_v zoS2Aimk5Fu(0t#tQ6O5K9w+TwzTHg@e{x)q7tto8#s|q@YVolsv ztsBFlZhj4_ltuX#YSw$fc{#j=OX6jo-D#Y`Xlb1^%f6wFXwm`I4vFwQW3`7Sh9+_5 zC}JnT2j5RMeMs%gFWQ1dQv{>b6phvxrF|cG1E#(MNDB>Ji z)Zx}?;Vj}={R}>~b_kONR&pG$Ae@MI(f_l-e&0qcCxf7qyEIL}lx0ZliiG~9-HD@D z_tdhizB+yCRHNy;w}061{<^~m23>6)#o2DEZvicNIvFZ&Goi%kh%f0sK}H{-$-Ir6 z*Mtj>Cgz+CWWpH+@KrB?^<|kNb4h`0uQQHA%8uxnrpu7Ym|&_^z*xi+oM0j}QhFZ} zZ^$DGxkW|1?X)0hgw=qstx(@Wls7di5nN>18Hs0cM0=|*yaA2uh?Dt<#70*}_7by( zMPzZrMB%3IP`JZ7P>r$X;96*ag-H7QRj04i#jdLPBBuS@t4nRd{5$cW&12f6b7izRI|H)=V9#i%m(!}sRcwy3DD9ci0+pB+!QIceO~O`ezob-1~Lpt^b}4g!BpPkybp)N%_xS6$^rQw(s`w^36wb_TH> z9RN2iFx2dlzN<3?XL1NC6{ZPThatgs3e7)bkyt%^;unP21T~CRT@;=6!on@m)QWK# zF~p7?T-wFaozmpV6Xkm(V;-RWZCm9FN{X7JsDI$FYmSd-S}B(xTPmTSU)Z-#NO6z$c|S`QYRi~-EROc6$K>h%X$f%&ee5+aqy}8o9(^*EIGtxO2X3) zNgD3YnDwUCR?6x#MS>`ddO7@;xy{Aq!fX%%iW5-Cv>(GamL7~(3#yNEF`}fG%z0R9 zTIU;V}?}{USw_n8i6U zM&r{1U9SmU_Ue5B0jWTknf=uV*m6=!UONPCMli{%r-f^KOhlJzNg_hFK- z(cJt=JlP5^EqIi%>Cj^49uR2IhX8=BAHSlzaj3kSSenuKk){?zg znE{1H_$*YOvCMuYEMpB(46@PsyM`Mw+t=sW4g!j^Vm8%WvL6n!sS6D#5-d3djT!A{ zBlDP5GEWLpdQBphK74m2J1@PIU5PwWEbp4#<338qD^~dsSI6aus-KgHjiq^NEL$7L zEuJak+@ZjcCW-*MA=_}xUX~#f%hj~!R}VdQDW3UtIbl-R{iO8yeN`nl-|W1}a*l~^ z_};mh@6Qx2r9{+Tq>|m5-^+)FM6^e@X|&E;)TT|CWUBAZdprS%I*f~l;EI~H*XtK% zQ|o-4DcXe=XeGyAuqIj%+D2jFlHvv_RJ5edI4cW%o$w#nRN%td*oI9p3*P8$X1JzwX#Uoi;c1(i#I{AeE3D&*b#6Cs>$h@uD9*y7VeXO@%lCW zQ7K;4ab}4e!Wfs<7Rvj3Vdd1#+awV#fZ19!#C>mLc9?XvZ|Ph8DYh?!%ZHQRzaX5= z+$$uTzMnnf{idt;aa*}?oevvm%Mg|{V}54cEiUjSRG4pBzry#|Q)~`#9R6wz1yDV%V-p*>^ zvTp}Y24UYRW(><`{~y}kI;zTj3mc`oTe@2b>F!2S0Rcg}r5ow)P)a%^6afK2P#P&| z6;NprP&%Z9Z?3)1{_Ys}?|aWU!?R%@7p!-^@BGdA%qM&i%?aL&w=SK5sxLS|eyRn^ zA5hg`}mo=GUvN8`TGxa%j_5gh0^y(W|9!b7RF>a$@8T4-X{To z{ruE5R3A#ip2ha->?uNm6hU}WpKPk+z54({vxQ!u;LFhC zALI&rS0hw5)86vWT{uo9VPKd^fI1NFbQ1%Q-o5;uKHamD=DYcBtg_Nh%=6wX{qgdw z+Fy_Ivn~>piV_SrlKMu}oA@%Iy;GXTe{x0F70q*$djL?|VCrK%tcoVCUGG}`AX&CR znoZMKFx1c2mHBf}A|+V{J>no`Gcx8gnGou9v`VGb&XWN(ID~r4u*48Smz$elQqB_W z^TUW>sG{RYQ-QtaqhLC|b>N(6tc1P_2hj4THwAL0Pz6&!pTxK%M|+DCP+_g3j;F&= zfU)0-wCD^11S4*FAX`UrZy4gF73JG0^5R<_E!KT}L8@?QiBP*jINO+;l+sa&Q(CHk zU!bFYm-kg$>a8WY5<1tXVA?O=H3|I=+3lvAd1H%VJpb_mcE7_&wb#p}BRytTd8Z&@ z@x2x?e(_eU6XSe7AesU2+krS}BXg6e;@=NzarmNM$A3f{X3_RGYPBThl zvjq+C!ORCZnNx1uRw>U10BS@8tpx2A#&1J%K3(6Ylts^gpoL0Pz{7G4gKAA7|iZzVhO}HTd!U_)FF#<&%OiF$1P)!Lj-Gz|Y zB}~9cXRY82R!?`|dT$=>6o^)vD;+%q2x9Z+s+2HB=WoucV*XSI)VpSUe6N(odHpTi zc$C;#FK~!*(P|J;IiyOPLm;6oRUSfQqgDumWM?0aO`x^|c7~7{>k@du=?l>@WzR^C z>!6B3^4gY}-U+-p2$;)_gq_6=y!blsW>aEeNE8)O^FS(R2`iSJ;t08xU$ z?IJlAn)SO3D@eDpu9n>=?mhBLy)T`z#r&7)SS61!*5hd46_SjyQ=SM+asiGF^T*T& zZfFAYgObv$ZxiEWsMbeCr;^`Ar=L13eW^znn+bz&+QTjEu zCw0vk6FRm!;zVWw(*3YX3DHs7!Q7;HIM%69iVgYWm&PLMq3_=jR~Ny2W``)J?re+4 zZGO8Cj-T!_V6Rceg|G2P;BC`QaxwuJ*1SbeLE#H*@PIrFV6D8}han(pY(Af@q6iK! zmPr*RD!taK+oq`v~L$4y?JbU&;GLx_~SLvkSsI3wp{} zyc><6Q-hIlI4I@@II!e5z0(o~B@@0N2(X=?+1fhwGhnNHgQ%-Mr(l!X3E@JtP_tjq zcB$T3pwj8!f!|~wIQ=IlckC))p5OwWFFeTfQvQrnCh)s%Sg&qFHkY#ZL($i?DR#^u z-$HIQ9|SuTY530l#y4;}#!bl$Vs15X%txtPSJx&bqG&%d+spjYVDZHle5>0wDVz5- z9K4@VnaU;>&tPF;83W~iY!D6!Ls$Y7p2kF;z-Z8fe;bS(BBj-cZQWqtQK%h+RRDrB znS?roj*@~P2haqTOzeGN2u)&;y@G|SN>>9sm`q3cn)u-S&@ z2w;hs*s5IEkO8wm(_S#(lOnvft~AISoO{MRAT}P{2I6jlkPW!9e4nYPsk!wd;sJ5U z1kDI|q|-qQ2sB0s=}eAJQNYD+J^B=56l?SygeSbi^YhfU-SClZ_O(Nm>`&}}9|%7g zRv($-I+(eX)E{A_*#&qHPGkVIs@mN^12UhI=EQ}-EK;>$^!}lSMtfj)d>SSldS#a4 z?d1iWl1$n{+0gg%1ur|uX)zFF!2pjm-5qldNlZla*zXt5!Q{-CSVja2kG~JVEqyx~ z9x^)G0)lY+T4`C~iWpH9Q_ADNK_<k%Lv^)+NsOZP2fZ#->2O7#jPlEDZq^({jNM4d+IqP;EzkR_YfOP z2GlN<(nZ7!7;QBB1^ptcrY4XS`vO+XH#|{5f(kg#;4(Z!&X43P-ZPgR-DX=136?^5 zPT+S@;xlM=+&Z?7M^yl@YK{Lvx`Yhuo#yG-;-=QdMykemiez!m|4gKR81lBI{Bjg0 zei^Y!@eIe!sApamSygu}AN}*Fvq_imkfX{j-fR%Z3ol1W>oQTJhi}YQe%ZKARcPUe z>MjP{=4F&>G1&C;*nUtM!yqa2c<_PvUS!4|WiF&LCC%XGABR^x`E!pkvNx4>i{o5p z7j_Uoe{w8{&n!;)z9kYdeu-9zvsD|vP^%UFmT2ov)i4}Y7{Whc6g2{S4e-+dv_t78 zwU5Y*J7TE>Fh>c74;(KuPt(1H;IRgO%OTOu=K=Y5p<~Wa$JyFCAkZLbLFP&dtcZ+y zdn2#g_AimJgvqh;Ho+&$67TLX2bHl1r`ucp{yzTiB>rkFk;BeLV|z|Dx~35#qQ=w= z`Cx%7^soo*Y!3n;zO)(5L8l38#+NdeFg?~UdQ(IsS%a2~8QE~&mVvhF?W*?V01xL- z$(`C0wyc!}IsCbv9tF+@f|`%>lz`YC!{4g$o9`WwkIeBEhtXC(+5DtCd{D(VA!>WB zBjEMR?Q62>hF^Q##$X{7L%Q8VY7(F4=73KxWvq>Z;AbnY?ExZ^EULySPPrf{jxcXL z17_3@ewjB1cUf@GK>h(uNnU-T87ncsg8e}^6*0vRFqM05f&)T7)Xeu6JCbLRLEaN* zSs%Jq+sh4R4W$M2kCN}7fdxOOh<=diEgNKib3yd3-*D-tjd zbI}}nA)+0FPR?)7Zi}kcUh{Dd^uIgvzCm-XlTF$%tVU}6{W0gBUQ#k?CHvdeROz^l z`jxYt1vlkJlfJ$Ih_%0K8G!v$L##rAWKwHeHrUA9_vMo>+|_r#oc?u;rll~*lN_Nm z1(*KLW_Kr3=IF51p4B+tk)lwG5BskZPKI=Hz3y`-NZ;q8z{`jb>;M{z-@O?KW#&i- z6Xm?hNd#2lDnMX~fh$Tm`68FqBT19+pET#qqf|W4*&QP}nK{vns zO4q5daVI&};d#G7)!fQ53{XVQRx0~4Le8J@?&=n773l^>D{apMyJ4Ak)`cu&jh7RT ziLT38zB04^i&j=9kujhfs^tqX8u<(qvsd4XhrXwfANU@&V({@&s4Lzy%y+|L%LEI5 z@~cF{9sHSRK33EnsneC(nY~q`Kth>-_=;S&D%}E=o#IS4EZZ+kEAn*49nsLhRoT1F zK=>cQl5hIsad_8V67Jw!EkCOP<+Gf=;O9*?JgZjtKnt zkZjwx>D+@9_M^*vM(VtPcvbM7@hkD;B=f+6HdtR}{X9Fi*x>hn0uMkqbm* zI5F{)C~Z29Z|~X5dmMgkH5|8&S1R+BsXf~^+r9We`<61?KJ?!#8Uw=jW8(XIxr>Eb z;(L#x#hE4CAnQmuG$g8XIo~2$wNw1U`rmk)QE__X!1GKi1A6UmG>oJ~bdrx^v-3{G z{^+EFdpfg1t^gyiZ`VM!F}g~N>G~g5eiifM)OJ*U5~lw7#Op%*KN3JvDP=vZxU~cX^X!68q&IM6^Z*8pm_oy+#^PIhDFM1Fm>L}I z?O_EZEp-XHQ@im(I6KJsr>3V3?5c981iAr4?z@-(S+#gr-d?N6DjbXNfl?@r(X1Oq zDKTAE2yue!0XV1+0Hb)EU=&-^I$xSH2O~`U);lR|EL?Se(Ol?V9WQ9*N2E}2j}1|L zw&AWBxHG+TV~tXw?Q8>Df?FS8%O89)XYY_~^ojy{R4*_>P$H?HO-myZ>OeT{wVS6X zZRo;xg}~*{0Dfx_e5M7`st7#*8^NHUpn#ePZ!qf9db)8uS~X;yU6aX#ZVLTMpa+gV zz2S2K5@CCvr;r$j+>Sd$d{z4#iSajmotW?M9N)7oG{BKFQ4gMII4ovn=OR*VJ@K42 z!K~??jy|y7i5GY~^0%Jw#v$!ZeyT%x6#}FYQ2gEdFzBl3pZo?k-@cHd`v-KGTRE^` zT9#E{hVeukWBaKw!OCsnYIVcXb}RvW8QBAL=5pgVZgdY40|RlVs-m>Ba`3>lu9l-s z4Jzq#i5Kg#&xHq0+$CsZ9bVsE|=AgOXtT={XTfjX?iGn9N?q%#OzVb zE2*GqD`H~O(0d%jkI$Zq`ppHhc>k_LN=k}P zB#bBd>K1i9-&bubkS}`&&B8xJ&1?R%^TW)1vEw?2H(;6`!}F-_&3%7v|J{Q6GgtFH zzaJ)R5Qi7DW_+ z3En7vH+LqUGDjnI@8z**0XY9|Me453N zJC}-^$g;m^p%*1=|Tf z=Nmq?5K+vV##0nBz6WL@#$31l0=H}lV$BJ7?T=R&)fYyz#U{)USz%4u~iPEOVqmKU;#SV_`9efSWJ9?9-LhJ%xZDA)cT*Kh; zMdHZ{AhF20@ILoOjuEtrdwvaieV5wu%cczYR z9~23XRkEwh(P-a zSjwzK%m`yVC*LdmHmt7N$a$O}O#d#Gv*`Qq{OI8KZZaqI%MqL8zat;BC!3TgG`A~T zf71mXl~giM*N1)VLuFXNRQ_wG`a$U?^H7F#;T!*hM3bs0q6{-uyY@=U8}URL7-8{P zH_JfcSMLf_AsDV=Uto&Zz&iDzj#U$b#Y3brjt1ASB01Sqgt8&$O-J!L;9tzj&@czU z6O|=k9TQkt`(DX6!)I=@z#0;5)ui?N_wUgVU7{%M#)mP^79gyupo4ukf5L&`p%iY= zT`r7y3dJK0{t`E}1FP89jN_A&dj!qlT|!_8uBXPN&RQi5E?zIC`~{X?VbMa2aYFp9 zq1V`Ce?UO-L?v@AS-F3TN?k_p?mq1LP_xkW=AiACUrHlMY#hPRk8BF3j<*2;I_Kx- zU1lFXa;?*-@(J|x<0CaJZ*dV8)(~CxR+O0WKu(u%l(2dpBJvV1^s%THV z6~p={3=H1!<5V-cIj8l*0;!2v$!!x70u}Miv$ke$ostI+9>C&Sp)E3ti#WrI%w71a`%R)<${*b{)WqAzOf^1}sfS5sE=hL(BbowwkGX8gzN_saIU2%erV#>K68F(HMu= z{pXz(xq7-{qOFsv9k+L}m{^JT$jB9@L;;`z0s9&BIXGTwCNmSD?A_aQ_vR@HfpBxb zQan86K{TqMFI0p&+I^2Pog%-h0FuD1>u!<**Ri@eV6E^XYP2 zE%#zJG}LAouEYnr(G8JVjC4BHvO?}};T4^a$Inw|tE z#GaSRMeF71S?i4hj6llj&MBF+#9ga%sORiDyvCwlNKnnu4C`K;a8yz8`JaG=4NDck zx_;S;D-?Z;oZwOE5DVh?CUc2_Ep~(D5ibeWkP$mIL{T; zvS!_ny4$hhu-tqbLdLL<>4LJRXTxr%U%1PEAGEP=tb6TjhdGU$zi1wM!(M{r!v%=(uW|dVDhal@UF=RJ_`JILkgAI zN6dXG%xby!H`#P|l;g`H(Eb!j2T=^XKDW6?bvS&9h2%y3RMur=P1>D6KV9Fhc^C;* z5U8m?!c!R85|rM=U<~IrQfJB}*=D_RVqx%$4r~u%vzoI12`e0vQQIoxhSJ$D6!>wb zJFwMl^ZWsxaIb*>f))RjgbiW|{{V>Q(uR#dl>ZTrfvzn#-pZ#DB+i}Y9z`I;VIT_{C zRmI0siQ%Yk-d{9STBnb$XBWjL%Ptv-KMzQjy6#-Yd~~>JzHl|OIzjV_d7ko(fT*yO zVVBczI-z*MC_G)y>Cg7Q@oni|kLp{+C#7Jg#04;r_*|LHem3o<_rN8ks8kX5G949L z-(9w`v$hj*+WpXW-;P~H8^=Uja?66TtSz~1KPr-;Q8JG)DGO~(27j~RWSh_Dw!@}a z6p?~HDh_Q_c@RJ)xJ+eWyP>e;FxSY2N0pSkN?M3uD!-N!C`}RAf?cb@xe{VK-|+Kc zIe31k(~g$Y*3^6iD6fx#s=f>G0)#lCge%VbGeoq6oU1n;0=2UN3*CBk_%W?I2k}c{ zO5k3S8lYPK=^?q7bOIT|)seskQ}a*^(Y2%K^1PR1(?G7K53-h6BC&&?<9zJ4;8(JO zUI9CvyTQnxU!z;dtmSaC#dV8t82kg1{KN?*$-d+-PiFKEspajt$AQPL>gXBOsg7Ea&i^(L)8X3k#B7gJSv_v;VWZn_#QfNT6>pVVPVP|u&Oef zsjw6Vgv?JOI^3wFnjVNvYfm8v{$0#YEs_TKc>1XwN4~u#|U=_KXdJlHkRjj5hR+RB* z=@XwPdciEF&#pG3Ly~>wmbzOSd|4CO&3Z5C3{bNd7M%~YV&!SLNqS+uSYGb2)P>v- ztdbkSbV3AShqrh1#j;+@_7T@7gwO+2IfJh*Q>hesYs=h|iJU9;32Ov!juM!cMe+r0 zhk=lAlb3hGn>zMj0GAuVK3N8Klm{I5Y$j49k}uT`w6Owu_RuJKjTzAhU`MQsYjA=e z{f+&p)e|7}0}D^#CW)7{QW(&Efb6xDivH#X8XY({+01MXW^1XKW>(Odv6NaB^V;|c zk-rVgi^qTVxbBC8l}mXQz3(1=fhF+q+ zc^!9C-`_^d#yhFGt-<$J*T)4zb0lf0gZRq|x0tbtZB_*=rXnnOYJ&+lYY7=KyA&QD zZ#`Kl;xb^z+v=g!IMPU1L+J&?>Tk3AquKgpc$}!RKeyFJ%O!dGNk8nE^*kE>aFAufy{RZM1P^PecCiz-I-l=zayI#N ztSHSN?zzB{#D(I^wngxX@J&@33fmbs3@_YjDt-MrtvY}NcsL4COcG^~jcO(JEj*LZ z)5O4;kR%&oiHAtA>QBl34b2lFLK$t<>1|nf%1$OTD$G$t2kHV(;X@#%dfsmjOH_%W zxF1NMDaf8eqSCn+MFo2oJQkxWUF7xLz`$scxPxgOS?o7yRF)V#&kei$YayT~Lw_b2 z;Ph(Ib=|OLE?RzD7zg48((zW|_l0hSGCIoE7!rH%#(1_cRK|qu5~P;4 zTBI>eoT1>&=X_yAn)>_^%=vr@Zf^!P3_!UslNcN!EjptnTe(Mn0Vwb|UjmU{>|FwoH^ zObX#vl{e6hHKOFb6^d+#rxbd5+7P&^VjPdysDiYk`A}cqfTMQ1sP*%N+-a}IHRzQ; z{fs<4JCk3~*D_&~82t?cFSn#pSbaVJH;z`Xtc@)nt*v1EELm^?DsTNHIiJ8q69JeU zR%~{*5p>-%Ke~OCoNIR(wre8;!Ny3}k!Rb=IrNj7{5DL~xBCjv%KMNPMa{zyqeLrIa^3%12u-?DF-R$h_6Sp>k5sjK=? z2CP27Sjg}!sGDH~_7OAozn1Ppr((p+$~KhV{X*%fjo4Bykph-FrwVoZ4r#^-_y`-( zcvfSm^!NJ`VxyzqD>8m42HPc=Ao!&^5)(&&*aTxud7;4suzw(^3g&BR`JWAJZ%1Ro zJl3IU?!k&WWoEXPC(g#qrOq z;v+1`ZO(_j+`{gwP~Y(BUQ~mXl;!N=yPz*=G;%ZzG zs4kC^(W&_#GX`&%HJ8Mak;9QGiO9mT;?n^q$rHHZFq^?r`ku&*XtOF8vOFh9>Orh@ zft_n~GLi!+z0d@)5NF({-E_z(aA%?gYhFPGcoGVq@NLeq2~C+;g<(gp0l+X2$Jx$`X^XFpq00s0NQOQV zKImYVYACA4{d)EB+7b?#n0{19VLAyD^wi-&?nLm?NlAt@;?)>}clqWy)^4-&@*)_a zu%4Wm4ZO|C38^yLuqx0Rrp_#nv;rXI=A>yANruDvGyHeQF&cgcUO!!DE^#pmmX%4u zfgEV;Q+3FpctVNbl7mx77Ok;~2`m{kHI!kw4U^~-Nk6w{jv527sRW>iTeZhI%=0P0 z)EY8rdhorpN)--@{$5<8X9ShWZEfOp=CGu^Z8KO52lUfYX0;i#{_j)gJ@`D=Z*)v& z{>(Bf)rQ?0XzpOiSs{G~QVx)6B^StGjUD-67w+?NR#embgE$hRwRe2qf>}IB5MXvL z#(^FcR*7^{U_XOrP5+3r3S;8elhrpfa*D6OjUL?Z&#_L*`5`h8tbjYT01=h39VQdF z!*4T4-6;W)FhG7(aM07OsIkoqB{J$AwY{%+o0u&B6f3f0`1gi zs6m{v-7$oCcu`N&;S2b84t)3nIxw_Fz55GlPpVlB0dOeY1`nBq=SbB|Ii9qI;c{8w z!Ki;xs>z`>1PL<0YYLV8r*N((%@i-C!j@6Hq`(t^?TO_V`V|R8ViSknK0f58Ps*Yk z^nZ*BDt-6~)=V%vugsTpfS`nP6hL@Obh+1nLZi+wD~)DxO#^ulmcO2BgZofg$^<5_ zuzX=P4enCR6!Y$|rd31MgBuuKUBRALQG~2WHdIDNISa}$t_}ysbEu}w?J#Vw@(kQg zL&z$#4!;lCqoNaJNG-)jsy+{d{R7?t=SC&RjyEdGlWq{Em3(z)CAPr~XJKTNgDwE7 zE=N~RtUeOYJ9q%0%YG>XcZIiZe^ovf#%gd^7;=5xq;~(_6*NG{&a`Q_V+iP+z+j$i zLOxH@@0L;&kOXc41uYOWIBgzE3#uf7GH)`XcA zl;n6yF2Sf$PCH%LI~?G8*t+6$DukZFG?a!VMA^iuz>IXDkPB%I)vsCM$Af?VQ-^Js z4-iq;1Ri0O^F+cC6JgBV5_0xk zwbv|9&`z-k`mSc1fpx_0z&zo{cvo(OO2{FNC?3d9ya|{(#QItd2y;buA4Yq~ zaxl$6Cn#tjQ3d*_(A#NH*kla;R2#;jJ>|Ix>}0ZG2=P*2>iw9|85|$1BG(yKPyOmL z{y9m62Z1p&ku?Fvogqz$L998w1jNm&Ccz9!fcnej!AuT98RwZQ1S&e)H0<(ElM{}* zE{dYK+l58z^5`h|=y{UBJe)9bb;KkHHzV2!RroZpRH4-O)1pDaFf#fAgPq#JQW0>& znccf|5kY{^8K+UM;pNPMC;A}Bcc)LuEjYCEScf!~85NHp?k{5;Rb||yoj*;Pv7k>l z2<7_$BJEPYA9{Rp9ZnhW=!9*!<5c+&bi|+Dd3Y}&h_Ogj=;cIe;vU$vuz50~UWTPv zAR0k=SyEtv@-JPsi5RF@9iSUai-H!GKu`TbZUydyQd`CkKnh1$NeOSjTQk`HrlVg( zCa#QrpYBQtqD7)*zW^E`&r3FqV4U)@@#s4B8zcpD@0E+Vds0U9U*IrFgg1qAcyc$< zKdANR@Q@~kTUB9-63(VoK-vh849Kg z|7F3^@3})5JNpd=KmrYtTmV~cLK+ejs$w_l#>8=8fnT3yL;Y3Mogr<7i4wtA800`P zGK>3x0dB;~n?fE-1yLM=^xuYgI0EDw)o6D`YH0o`v=+rQnQ%HoV>6n82pnYPQwMS& zvJe*4+QzHTHFq`92EM=)E6){ItAiez7%Kl|10FDD;z2|@1$Zn~VEKY45{M-fGl;yH zEoFP_W6xk8Lpsan)Jt>4-vKGpM=Slf4YCEGe-5@BWaM)o;xC}3rGV*@N2r_+tLi~LekL2$vVyOL3E(r_Do`((@pb!(z}C zBHD*fBhCR14E^{FO9wMDQ@${L}C(|2P+$frZDJu zFD@>A{muf3B&l^%PY8TSaQPI(s03}|W;Lx~AG-1!&K@Xnh|HUnU$7s8Ab3;a$&nG< zr!6`7$Y75bpGL}YCn}r{oZBTHAsCeacrm&z{Q^vhF^f^&CTfbA#Q`7Y#VkCG2ozRq zF_k1Lu-XrmUz`JOjUg2lX@<*kZ;yT{$dDN+P&j3(c#lxZbUN{*rj=T` z%vP>*jp*yB_X&}U-FVI48tU*yo45M{6Ae3n38_&r|5t-3=s>{Z1ub0hcTs{fkOQ4| zs;^C~vW^rv_sO~n{D8G7#Wyoj>h9(D>odL|iB#z6ax9RK=7+LXMHT%|HIkxm565$0Z>JiyPBDs3*>RK(axU4 z92Jm!|D--r+=<3xZXMbXwd022j6zrMkB=E8|3Jcrbd8FZ_JxP#OHlR>3^7_=sT~xO zr98Cu9u#i;Oh}D?_uhHzgdiNCjbI*T_!20Ttvbcpa_fVI((PiIcTokdm3wjIA~@p< zX|(X#9L=)*txIkv9W0%QxEGIo{!G#4Zr^3t)%D>{VT%ufLz+njAthobeBTkY za2_M2hH%@Cfd@bIsyJ{sU0gwVo1g=NBWgdI4n8NHu9o+$M=Thn(#?c`^Qbm5OtLruE7roJXcQ3DYghlekLqY072gSb!x#vO_z1H0WT4`I9R8*Yl<9Rkj zVtanAU}S&*rvTH2z7MQ55QaoBxl!CQgKk+-ec=JZE-r?{7@BcNs*p2}!Wk?=x1Pa4I-{47%Q0_EtMx2Dhr~BlNJ)x(2YaxuC|6u{k z8dMDhNeb{_07|&Aw8Z#+#;{W2NRSMc_T6b&07V!v1gjh>tWAlVCc#eapF0Jx z07m7MXGeejz(sfnZ(=#7%L6(tu4SpfBdq)C(4o4zxb#&%fdz@Trzf{=F_IF_X)S7g zUS2`~13)c$>mE`NnaR&z4?hZo`Nzk{(S+X=mRkMytw30>f2Wu+L&{v+IzcLi1A>CAqbydH7-41gFApFy}K-#AQK0mh;$H1qSXS*ts;{vc#m^nHObmz+yqiPuM- zznm|fm57`iy#Na*Yb8?C0B+IN9>~Aihllu|I|+-4OJ0zcv{urbr3{;tUCs@NOOtSw zD{Okk#%>7-8UB1M0%jETO~Q9>$FS>n`0q1>Uh2KG9G#jX>DN5LPv|s;lqiS@S;2qG zi`j?se$Uzp8!qyJZ4crfHluZXv|JK+_0re+v0zw_Fwbs1=JG)P%Ut(85G=NYXOf{0 zc*=d(2?So$AIRjHOWvj@$qgj@v2;Z{%^0^yNJyBH(a%O)t3LOM>?JK@1*}OOjhpa- zESfuuoqS{ZXRIy@9do8C%v|a=Hf!KY?*cA;FJ3h1EJQaUi*uF4CWqR|J-IC`{Nus& zKfREU)rfdJJVf8hi@S&^C{D0H;k(0G5noP`#;@>?DD|Ta>s$?H{g(JVfUbz2tsaHA zb^0`MaA?;wQ596;l9aA+-?D(j3VxW}9TKCOU79jIaF=I1s3xe>83-^EQ#=pJz*YQBdeAiOh-oScI*Gc#$2-iYg{ zFjIVOX=O!1OUp|P?;IDMKtUgyfq?;(Z15IfdCydQy$AaO#QO=>1t{oATzou?pUDti z|I_22%SJR|FE@_-7xRc2@k93I5kG`QLIOVIFHjf0rT+5<&*dK>hhQAhwjN_JMNwg; z#Dxhyy&OKI8k{j(9l>F}NKnuOnW8X~H)@_`4)%@H@#MZ@eo0Vg*Te zko5$)7>~i#J|0o4()e;94lXGG)T>}MvYZ*ofS6F>QXDuE*?&O!=RF`UV8${%?LSup z@rU{!cqjjTrS=vO$p1aIFfmBOs_wt9GImN3sNui=&opmB_(lHvsyqmO#=l=p3D~~Q zX`Q3Sep420DEcNhGCKXJO;@~q==A<)5_J>}8WA2#k@obRfzclh9nED0$+=2X!vFWD zZ07Xe{C%H7D7JUlP~zM4^3Sb%^2C!ynVbR|=aR5=9{^iSWQ|Hzhr zIhrIZQhbFQxb(2E&$@eSy$38!Eu=%3V|Q^6a1*(TJ_#j8s{iYhB`le(6HyA&Z<@kxJi4lmSnVkbC<<_+Io zNi+^=gyxjJrZIWLZL`ckZ~e$^#x11F@zo%G1#e(>i;$=QPEwplqaeK(=f*3|hZ=eO zE#rT@yqkm);-0?HN~V6f*LlXiHD1}mzniXLY?zdstJnMEvFL)*hacF=NW^~Ma69)U zHvIW8MNLK00WlNmZtC3z zHeGw$pCT=edJ~t5v)3bdABOu2L2Z3Nzh9XlSb=rhu0bGk>}X`k;UO8x4N@wK$Wpt4^$YWW5t3YOnpb#o z$T4?YhL;^?oV1I5C4YK}d|#MbHg^~D^k@<)43_dgnbTDx{17B*(;`feoYWvB?9?!S zeK1n>IeOGyxKSQEeUiamp|SwylZh01^4{$`vAhm;UVrb}{JAOLDOw*rsBd=_3m5X( zY+|hc<~(I{RqG(3{!I4{!LnXM^gecc-TOY-*9H46cL;V27ROy264N?onyyy82N$z@ zj~0Du>ter}P`UoL{9@;dw1XcX?359Jp$Z+8mbNymZ@4QYpl$$SG?vB`Ic5RLH=uR4 zbs61M{P)2Qc1x;qGG~ju;j&41O(7qoIKJaJQRMG;uzeL$eD`?);1M z@oI1U$AoPDY+PCk#elZaIeG5ka<-zpwbOl?k=3(^QD1h+U1hSoL#FE&gyWZG?OF9i zSNvaa$M>Uus=tbB({?@fe~gtpB)t0fjbvnuQA1-h|FGx?rLx2k=gKPz-&lI(p7}?& z`06(Gzo9fJu&^1gziYvu$iFBVsSG<0_^53dt;f0QHdRxv9QmWcmi{eA{cE$DvyU$0 zfvSvuIzl@{MFgqMS6A&j=!`3ma=B4{f8RGXc}IJkLp4+4q9 zd;CX(Q=Mn{cdsdt@dMyYy#?UB0n2k0PyE#8e^1k;E5 z|0?!TYFqW>KF2bt^H(`Z{~JWk6BI)>dE?@CIz~bJ&i%hD#c2h;ISM^je{q!dv74&* zqUR`toXBTY`vrdIZ;g%9d68(ryl=sWljWi7lp#M|*JN+H7Q9UMvgHpry;>#u+Z{_R zPu!4FVbnt*{QA?+%^SB~?0A}J6Z*%*sw5zl)XvX#H*CB4f3TwX^(f}kpzVT}=I_xs zX~LdZfLiM!Y$+~gOH4Ek=xSMOehP+eGO*#at*eM#b%W~2W}td@j(~VlMRGUh?&#H| z)uIpI3EW3zrDfKhk~b^@>4|BHz3eS9Hn^_M2-?rso!pf*x9zyL-5Pi0b8>KBujxBf zxU_gQclb&s-jmqlZ@Ebzjk9aYes82I=OY<*!pV&$N#As}$CTCvq-D4IKX!7T=#g^e z_ZznRYp6){GCZa|`;eQaC+xCbh~M`2#M*Kjx5nH>=!>YNRX&g4eAW8m6?4cCzq_nl z(9}VS$@FJ}`#DN7Tti&$OW}G|x+Or~kXsrAz2{?B1wwfK04s?t15^X{=o6%k0DVCF zNrLhL(LATpZ~y%H{Pr3!)`6~UQR1DGlk?vJy>@6h8J)JT8aaOA^KE|e{Yoj}WMgIh zug9(YyDvW`yLF_z$mRLGUgX98`Gv4>x>izB>5r0-oR7@JUUS5>``0#|+)h_PA^Ec7 zu?zlmC(h>id!Zj)6GMG4oo|;7Zcs@VUSIJ=E2-VHQ_)ac?pzAqNG~KfKFm=>4}VEe zq$o}M;8gY6OMIqp*1=Pnrr^mjVY0|HiA)+x4cE7)b}A3k8UCg>O62Io89JmqS`A)* ziEH}8(S9*BNY23~$@g`a0oTjsx$8syEr${ke4+Wdp0(>`mQtCwOs=yz*Q)YZ$#Eb3 zx})of=E7UQSg1NuKDzjhCB0lRn|#MAQD3R~Fs=}{Cd{ru^S7Sl{I8f8qj+=5!%s0t zh#KcLqyk7dm~O+y%@5rCIO+7Q5YF~Z8L-1u;1m!%_y5}c6Jbus|F8$J_^-{*v9ACR zeRc08H7!h(JO-6X$;lr9fG7g!7=R8uP*n9rq#=JQ15g|W0y;q(tYFYpfX~qS)>eWs zkc8+ZeR)?By0Bup%m)7Le$>uad@O~OlJ7aA2!5p=cchj4zLaF-&t#Ojs>3oCpepx# z@JaXD;Ht4EWx?O?gv`%gBz>jqXAFMva@orD+k3U&R%!7*EDEZzt7&s_CnV{d-J$mEsT_J0baFLhsiX&nvbKI&+rxHlPmt35W^0Pz^O* zm{K#^&m!}Vc~v;wWP*H1QF~eYgWvhy(rP)mG^OG4!N_3Alb5u-NxF37-6;hLe?wJb zh@NZMiFk9%T{lulYnrr}Q@U@H|5-XcVtp=P0UUqe*7SM+fDO4;YVqg_k#FAofn^oA z1Ep2&{f6LiD2kx5!Z|Jn)Eovm1luBq)e}Z91O__-TP#!?0$>P1z(XA6X*Gxh!9^3+ zF5d7TPtS;PphiU65{*EBaf8!L6;mTZe-A!x-bX*ZD#`xshb>SP{KLLqd>rd~8qIs3 zTyVFUjYwqYZ}%P1_g;-c!V>3VD+}!#*s2lhA}t|MWnH8f%#r`Y08P65tm4M(azjMcRuTuT-_h+74DT@=Su=fJ#0#Y%3#ltweey`~H1@G!P}5g&b`1RE zYfs#t7L{7QRO=(hP$l5h3de6fs&_7Nd1htDl3#8r`5mRaR-#T!PBE(8P zt8Lqc=16xj*IvO+w2_?S`$k*wHMb!NTGqs1j%1`@vBZ}L%60GdueU`?t&&cpv5Kbq zPJTMw(+`%ral>q~=HvYu8b@>%F#O|kl+&OB+t!ALeR#;h+fN7Lc{Mdh0Ji{_T|prs zvf&=ER#{zNrywU64menY`{b9-$AyK*D}C`aA}(B5H0~|D*TCUQs!?(q6$a?CV2Fuao+S!267wu4kGZb z)@T>Z>%na^47C5wupMDZZ%S@&59$!r*GPjif{>y0MG9h&+Qjo7#NU(*d1_9VKkG=T zueKH{W&R?00X?+IJJzVdC1bH;o+Q+sXNW_|kNI>+R7iz42s!BOyv0!pl^5&m*tc0e zUX|46BJ3&+nzAUpY|_R#eRXL2sglIecuzTJLxXh}>#L|dH0tPATq(lE!kZn~r$1WE z*%qwxNYULa@51`X>&;$;U-QV-j%;sni$z|ITu(p+qq36jK{6AiVS%2F(0#2BI(7qt z3JEEbix~pH=I3<8sLNgE70B>{f3r#s)nk4b$>w{)#)Ps#4Z!WkY`#SpfdOhf1otF_ zX97F>m8_on0wZb>>{h_rq`Ux+m5P#*5;(Mh3H;}8#^X{_Vg|xDfU*Eqak~)FaD*0< zGzBW}h8}d1QJ|OqgWM7+4BE@5)%~TMv6I4c+*eK&;JrR#P!wesDNT<_E15Px&G~Wu z2_Gp)l6RPKT3zvbn#^a>tCwtu_kAZ`Ugr70U>aJp{4r|Js*Y}`lLT(DIZtS zn3FOyNeA|hSs{1pA&^M`kjl%+k?WZt6=Y=W`uepUV0wUK;q@Na*aX+G{98fRydKV1 zr`->|VB^%tB!6t3ibk_?7T|srU^8}Ox58V2`4;EdGc~U8Rj@pS_dW*v7s%b4;KE}9 zZY)@Jf}Y?$Gs3G1>=`!501%lFqXr{E*h0aNgFC(v$aGk#7GP`&S3A*o%R7zbC>;XN z6gtA9O41WMJ3C*$_JU1D|KrjRsSJNWi{Rxo9q^v_f4|*fKPNZ)!{?5S9Vf%+1%*ZU z>64pPPT22@*Swf3&`mhK#y=_$oBr5I(s7=TG(&KfFE!BlH8+N60Sve>ez$MRe&AD470N zmu*=s`%lyVpTA$IUahV258U+6_w@0B9sA$k`u`S;fnVY~z+C^mIMXJ*!G9PKNn(3@ zJ52lB;6+fOgZv+uqqY*TzY>l3J^+pI{p_m$`ip0qC_j0Nn|kc~;Jwfe4Dl7~%w&JfM&Ns{~l;w-KNmz8-XfaM!zn=^`Yy zgYJK;XbCpfoq%&givX&C`7X5Nq$FTa%Rs>f3#NAv`=T!h5(5)$vjK;4Xy~3nZ}}LhFf$c{o>FF^q>^ z)&lbJ(1|R-MFUL!O3TVB*4V*CWDrbKl~R8$o2m}fl%>OpxHI1W?afcmbjQ6wfQsrbinzNvcb6<5^2C#WkKcHO_) zp=?2O4M`Wa8cC#3%qa-~zsDhIz3 zOwYUU5W_w)oI?gce-uoa{?+Slh+aG zE9OyKJZa^`3s%b1XbfcIPV55BKqSpjX#xCi?f1Z~7;*;-x`NG(eWNbdm@U?eDSEgM zaj2ddx4JX2Zh|!qTpcy2G8yCu0S!5$idv&y@!Ws)=xi(aZbjp{z74 zEK^@jYsg%HEHFq=ga6IpLEJrvM4otwu=A@uIX`yhgcVDOMA^NG9z+z}2S!Ay>P<3uf_4lv^W;vWX`ri;lp&|(6TSe>`>dbNR6*hPy zfcU8Oe~5eYa4P%#ZP;v?7nYgKGDaez%*j-ip;9SBWGF=;q|8Eug`zT3q*9_(WG*xr zOPWj-N=cL?z2{Z?zV~xH$NR_cd5-ru-u=(s_rA+ouIu~#4Cm)O&rhzNz)3_Jg6++# ziw6^90xFy%O=m}njs&wKnfV30Lthei-M~LtOlOlLll$?!?MCfXK05_xiy3FOF+y^_#xs(ZSco8hn=`iRowa zdz>Tr(7CFpi30ngXk5kp&}xqxbBkz#m7vhMsbaEl)zo&_IX7`VXZ{2elf+xAXm$L` z261$;bOr_nAdG=p2I_T=2c5-x@P@o!V4jSHUStDs=!BNH6*S5Skz~N9fQio#Vo6CX zd8=N)j}uOq2+g-{oP)Z6cqUc$*nYP1Q~}p6EfD-5uZ_ukoOt-{KE7_@tC;Q77T|D+ zj({QvyQ{b_iS)tYfN@uR^h>Tjt-N^>#gj(Ny0vTBg;vxdyoF@kKKPd1W?P^x#?`^F z!nVx&c@@^5PNOhHGpXt#eVm&5_3Ia6PNM4Th6u?6XX2lf2w3lvVlp~mccX`{ojdmy zXvgO3*O#06l0P$uGxm1VeOsH!U1otQPQo#jpa=3uQYcJE?{{>trNo@ty1M@R%uMvT zsQCIr@443&3M#oLMZt4Hh+zZlw+@Z9({CHY3B^65)$J@JMZUf&w|9lR%C@&=!t25^ zYV{EEx^gx-!}kLP=zDmrWn+7Ze2oL&(2xHxpECh|Hi^qFzik zc!Pk_&)X(P%Kinx4__~PAi|R#?{!10OX$ucDAHRijUQOgoDuP59r#)$gM_5cjx z5$SDXD*{Ho7MKa+v};dzyTXPx{%Sb(S93FuoaXCCqfausF`g{4U7!;|nXt**3e zppG$&ee5!VOT|s0%~Y4%+MdJ*E+sHZCTa#I7M77yV!HkXL{|S1DfoN5!S!k(>Kf|J z!owURx?5?^tfp>CJ(r}kV_p@i;@dU~4xXs7M2jzKN&z@XuF@^wE zRs#?YvHv=5=(1%i>`zt*B8$h^$5ccbuU1s=tSUfeH`;I15{$%$EgogAc%r3DRUnC^ z&w(5m$8!(`?0TpcAWw*Wts%FpPX&@&A&F2_5El?Hy(OoLe4UXhTi;eztA!1eao^<@ z)*uMdGC(57)1xyl^qse*^M~sZfH75>uo& zBfUwFb=|~xYiB2WuJx=c7pMB;mEEBec1;M@@w;kp_h;9 z>iFdpkzZmS-o$qw|FRt4mwhM*o`bGsJt#jkJpw!r(qDU>cGsckj^6m$(s4e4yEjOd zhlS?{EQ4!VS*3k=vp*3dg|OK&T`9)m?>I-ty`rBQD<*8zt1M_(;D zj82Z*Y)CakpmL<+nFJOB9_xw#^+41i3&VVnyvv|wtGaRH?!mV()&TuOU;hp$i6CFQ z0)7RaauHU%Me=+E`oTLcI{7w=C|875*hx>Ms=Fm7B_>)ThxI=_06wwC^c8W@KZUlt zlyeaRglDZ;9C;=}%ELQ(>cr^!KYdk?658T#W< z8iPNY(!bwuCPUgZ9&zeyb~eb5ZN0s{PoD7PA=7l}PYZlPf&tUK?e%K|Wo2L70!f4L zH2i$F|Nbh>Yp|6H-0;|+XjVE6ilKj2ax6hNNLkv*YfeQ*V z3IF%)>AS&hL=HqkmRs}RuPhICo-i-3bnx4R5fl^zGX(9|A4UvbXo(xXMOyWV%a;i$HS7doTVIFi zUt?nXGGs{Vqkjh53bj^BR!e@bwD=EG!9gOx#u)EfGzq3l`Gj%-M%YZL<>F zDpPAa)DZsT;9t-nOX50P5ReJLiOT^Wfkh zgfjrt?3<$!Vrngnt=#O@WbtY{NOBYKA`8NLiEZc25u>^zpKLMdQ56-DZu zL+>|X$Ugb3@(l`IWY`TGHt6f=iP9__9SK`_)F6c7gHurYlv5c)|0qcCaJzo7=%=HvwLYT(v(w5pE9iW| zsyhgPg=yrYE|D&(PF-{P;2ULh#6!E!(`zYu%7TQ(M#5%e>1YYBy%$EUs`) zh)Vk3yHL9>)|oF~qN2Fm-0>!{@CMsm?ja(o@4OxBmXA71PEmWd)U{vs5gepZ$rxY6 zZi}ca?o~(7KodQ92iH_FDC;C=Xy}0)d(itKD!vAVHV@!zj&6WVv+Ndse+?5<@?#)o zCv1jh+;SI{QHP14mLSj`cGi!VdWiit@5aUgXUFX#B7WnwRBo?fU&0F%5?li4-!&zs z;Y!zI%#ploo#@k_Xm#<7U5d=uEZ71zJ9x1NcrG7XW?=}30<6SG8Oxu5MVP>kJ*EC zy4VLOHk@6+h(3>mtYy`T<-z$wj7m))u}f%Q`^m_}K$5)L)9r&jWR$=hlwsqlSr)!f z%7By^r^^sTx20b0fy_LPnH%VZ7@{WAOm~FNO$sy{mEcR?L#E_4qS!Cjb4XCpZvykU zVPR6mf`@kLBY3<_Q=B?8sK2EKUAzwA9QvUqAoC*CGvwn$m~x&0BiG$>MwNzs)mw;% zo_Z1Qra2eDTJ4qfb(^2&@QO-a11|6lvIxsvqiRHm$beoN?!e^TY=9(|*3Nn#KKy;@ zwvhyX<|e-HvgjYyltk3sEgfTgM)E1DC|J(PVu$`e40ZwChkNF&NR}HF#rSE0<+6lZ zEJA4(_Uz$r;b2x*Rb7M`H%e6icAPKIaW=VrPx{n`iU;d3#B>qOr^|Pl+QA)qe0&^` z;ufgupW}jYxfFVqWtfOeKeslYANrN@1e43HV2a~#j~5x6MSkms#W3EKX>`=1%Il74 zCexuKt!&}($B%>H0SkEabzICXTitG(8jruO*B1v@uuR>mOm(;2=W`dM9#hON*Iehf zL#j@Af<=0ZC5LWYef+NZJy0x8ZTgyH*bV>qhv*<6CXRe>FUwtad|OA*g2r#%*7WSz zR$X}9o;-PeDQ+zys(p&g`Xr-QPk->6GrMNMn8DcUeZg<3u_Ig{pCfQ7irC;8-Y0Y1 z=5i19IT+QKwg)nT*;tV^2R(+Hs`uniCzd2PgLnh{IkfmC>t z-hpzUk+dOrvILzpi(LVROQHuppjt2;YP=)v-icVtEAdJf3!m4i2Vtr!M{K6|UZL?y zLPCO9h?#?v(@c`VGv;Mv5y0Fpc-VL^L|=~K9I;?zjge_^x6z+_J+Yowf5i6+5|YU) zBYUV%0slBi+U|C9lNO18+)6CPVXW8}VvfgUAQ18s7tf-l7tyDO<@FZfhiN^AA#6oL z^cw(8!W||8$q2D(_ydrE5_P(j2Uoc^(she;{W)iUQulhaiiEHYPK{+^aC(cn9d+di zL~{31C4WO}eg%6j{ew*D1q~KNu1+CbBvx98d;$Ux{Q31!bhYClO=>(Hr^=>)=R6ElEYEUC`xHOc01L=^&8l6>*i&B-1+T+|MsUa zE0E?hrXOm+789p=65~pF-~{gZp=EqsVP-$(3RcC{R-I7cb!5t4b8swM%ZFA|Q}g&8 z{E3J?l~_s8I!m6NG+WcwQwWOmYTrH!O}gAfG5fc%dr&rxIncBH?2h>IIHH`P2Jqk1znt;S<^7ymMJHY6^jBP@rn-iLZ zQa(u7cG~H7JJkV-%4S?uHe2r%iZoK99hnjYGy&baDeE4P z9h)WJ8mBUNnu@euc^#Idwp!^pW6N3#tI-NGlI2cf&=4P4O9dn?Jcc0^Ov~w+xZ7FX z{nn3AAI>BHnjR(enXhM|&TQp)(bBTJHGwyT6;WSsGLdux&4uObN5)4UF_+MftA^C@ zh-#I=M;+xDnZu~LrKRmWk4)0QVa8L2w|N7y*xd?91vk6#9x<9&8@fkHy!;<5V5S7g zVtPXpHDFv8Lyu1I6mF9cF^JTNsVHOziMzUymHV@L{O@O(I6qIUb=Qj*#Q?C6S=khj z9JHW;tDm7xi=j(9#|?j7@u{h)w#O30$%Q~Jet*GbivSnypr{&tos!PU?+$mzmojngp}Rp@x&ibb<& z+I?J{KG2x2DSn8m?F*Yg%abRSSP*K}sdu9Oz#9Y4_n)DJ*c*;UuKWb=;lbq-+?;u% z{W7I`!Zr|v#AMQDvE1{hgvFBZKvRX#XFI1l`%bzT$r!$?-}ndbG&hn4r6Gd0(i|_Z z3!Aelrc-pngb32fORKxP9~f&euIkUhZJcMqmKntcIkI5M$N;8(&6pkaCqnXY`_?UE1EXv#>2Pb1csG$mUf(VeuX-P zAGEz5izgoXGRG! zwQ@aFE-RXSI(Q`BaZRBJ^6!soqdquWQ64U-o1Kl1i`kkL@*AqXjhB1`9+(d)iPG<0 zLuGHR;->H83ip*%0FRjb7vAxD7?SqxN(sEn@00#hDxlMauGNyEKKhcoM%|-cfw#+}s31yvX zggF28>t&xX|1sGT@_VU%AhZvwO=BUiNtpdyxQF4I@dS>f){TKi5}ApaBoB}^<%6qe z?jo!Xs5br29y&L);g@0ihR?S0 zo!nT9;(L$3l0jZFOI#_6qDiKpDs1S2Cgd9CAY?NPKPjcA5yV4aLTC1$PSp?tbZqxK zcj5#gWQ0d{)yNO=VR{wanuLVtdQdW_Q3zY9_Wx|PV5l_$#TKU9d9^V`m0rn@%X$pApXSnllzYyzZFznUzXs7ER z0>SgyN%%Xz0vE85t8mDoqY14c^k-5kKn=p-=3sJ}(Dh!wzDo2eZY2IB;gi0$kP0yo z$MaI8WaPxzuU}1b;2{{Lfygdo!iUY%W^5?2&W}aA4Bvt*?Mr`mH}5lVR8*+h)f~=q zhD)7{jgOc41v?UWBZytRk9o~-YGv6B$U|hI2CG;(k$(DB{CW)f# zNLpYnqF^=s6rO=X2~1e_tTmHVQK>*5R}ehNKzMvpi5x|WYC&M_@9%%{Vuu#Vs=}t$ zC@{R}Xjk532gTR->7~SGOi-{ilVQdI^#kShCsHn6m+R{z9l2lxL-u~7=+X9ib=jPHn8{827jV9V3ic1 zw?>O=B_r4I4^cW+E)nGvoK&}#iMbNK4@m;6;6S6swO6qC`*f`F3-npYgsiNrF9ruO zy?cuoNHzNFc)}z5^5MgMSTC#b41*l3rFsE>b8mV~5DB1E+Ox}o{ds-(556t+kkply z%EvN}Gf#(uHM7aqX%Hw~6wipshRAaDj`Oun&#$3^&U~8YZlw1E7*FB;Mm6PSYOBI# z$I;eU<_$#>ti+Urv}M$6!dx5;NEwF}1HFk&Tw^6Q;Vv3vxoCHMu(&iYU8r#$cA1tu zrj0#1`yFNsMT?k|9l)4I960H`nTqja|APlj(p%k&P?sk3n2dm&B=o?%YX-&z4)^ma|+&RK6odq|<+52#xcjztR-Jud4Wo zX5GIf_)*TP<>J(pQvL~aID!puXb``84vokUR1{&<;0 za#z8tW0C!A0|r@`98vcKlQ8MIaLF4>lE1>;gjfo!NNmD${c#w+BskmdA|%cke5mX% z{43)@{Hyp)Pr&$*&c!`1VmJIX>i}5Nius7K(lAw>03En267HoKs;h4!=0Uau@4IUv1dp>b+xGz2jXS__4k0Q2no3y{Mh)7{NQtX+`w{o@X(#~&x zV|T#8#Db3?0VHLt{)s{w`K%*4JDcvqR@%+QeNQimh;wsuW7fe(AA6hLbqZnlO?UT7 zT)yVzus5NST`gMF0+~waJWGJ2BXS71!7nJ__tMdzlNw8H!F&baQ#8{*_<`)}Uf%%< zI!==GBA_#s9z*O(1d=;C6D#t0a#9c7rR6EZg3F|{F4q>dF?HgVyYighJB9Ep*>-8? zoh@I?^qH8L!1E!7+=`K5k2o$m7Z}kq8C~wq>*5{Z(*-hn#gSh$ZCMoKM1f2*mm1u1 zXa!lg)S=k8*v_tqK>Mis#^hTQvO%U(kxWsc5gKIabfcj(8Xc2VKn0n`_uu=t?An$h z=#Fu{BS5?c=5`8U^z+@H+$?nqWG;(k#6F^3{s8tcbcVg_4%&MXIM!tj{MO2wV7mU% z7o6Uy3z*n4ZpadK`l+vLgS6$^Tmk3=nDm2Tg;8igBX&3JzAU9rNVPgN6BQ(1sGJ++F z6eF#;?7PI;=cx%Xsvm-6W~HJ)v!ec4?`fD&mE>SgrsoH;vvKTkU%0e+)DHXw*~v6H zVnm8+2d%%=i~?C zZn+~@x)hspF|sbMx4(KNonrF^oEr9s5E=b;MZgMn9vptQ7OT=2k>~T*hT3D+nDTXF z4S>4M&Kase3Nx`72~%5B58fHBi;))rxY^LAB4F&~Dd|8T$mOkq_VGSQY*Kngdm|a5 zHM$t2Sfs-+uQY3i;b2He2r$J$WX`hl)3H*~t=hp=wSg1%ct6NcSnfp7rYTI0g3RRR z4H&HP+Kq4crs*#wEK0s5+lycB=fVODGjo%q5JNs*QSTLXtCR1Pw_Z6XXT1i^;}M8$ zDXf@#0O-Y-iG06m$fV#_pH~+jje-)KxNxZM-GZ=fNwip30LdP*RMOSxihcj6=LxRO>fu$&moGn{G4t8gC&=U zrrAd=Y3>O+Ma~|bl`9cf!4Y$F&TC(IaiBp$XTSJM6uD@8Gx(U9m@WAH3(hyQ_J?At z7&JUYk?&?gdv>wxrfSW#YsRW`u_r-DKc(cb2iKPB=lZ+2O)5BHjgo~gJ{J$$>=Irq zxDZY>-uDY<{=ot~qhag_O4iPueB<1Jc9x+Z6lF?k!IZExLM$BIoRQlFp>4wo77nc@ zG4Rpjl3@mEzKhzfMN{oEl4;uf^wv+7>O$C!5ewIWdC}@p%MW^7+Jwm6*ANlmtQ2sw zz@p1t&V$yxwdV;x*ZrVQ6UZVZsBy-ZAP&UDUp@!+gCd<#0jZQ&_4#gZ*;eOYZ zsC&n3_b-NzUQY6&s|>)#bahox*~n=otCam6;M^;)jAk}lmG(MB)&iNyuw(-~S|BA? zW)B_IWQsh#ZO@zybsM0V6Wx5JrY3$z6>m=Fh9lBAM*?)}0okKbM;;&1lI+ zA7^YHcIB=p5I%tZFLT)HTjh4T4((q4e3QAin|0)VToP-1psKD^s zb&g031a=wg3PhJk{ChZo+2^kQ?Ip$J{qTXsMB?(;5}}YJ_PanQPCwYx5@TLstd2j zcsbKOBs6q0*t4ikdzKer#DJ@D4m&xPG$76i|Fxja#QmRuIrEly4dL!UQ@r*q<~Nvy z$6a{bh#85V%IL&IVkLeuKf#}s4kore{xPrsVYR?4>Nkpsq0}c}*I9i5oe`mrvPkHJ zE}MlQT75;QV0ieG_+okpptM*(s6Vj|uxNP`l0`0zk@7Gke_iEy0_)=`I%(E;GzwL? zS#b-?r?wk)8HeC_mZ)lR=Y|r$J!)}Lkz04}z)fW+?;*UNb~-!%D_>wIB>nOrD}YRx zz1r_gQ9xr<<+K(k1Z#7#m+>wfCQ!LJUvrNuE*?e30^&yc4G@5L3E33$O^89~;Vg~K zATnCW~#`EZH-p^3QbC!#x!g-0^z%a zEp#GV?FuzjF)hi5_$887w9C2px**}>hw%k~FEU4Il8XAc_UhHEMMDXeFiK<8F(%QN z+veyTAm{+ZyZvE9P(2LfVOM}cFy=C`Mvh4G2L4823>wV|R%;E!y1_UtD3 zGF{BA`*@=sGhr?5O4LFirD4rb3$foDtm2f4GK;2{FU7Z=Lzs6dG|&PP9ifJH4rba4 z*N!X73AcRhJhx_*l}ca=yhprM{sW<;Jz+sF7VciaZS*+u-WQ;oBYTnGrUmliFVLNR zgIdC>6~{rqcAOj3S&fOC5C(-W{`!TgxRR+BR)qfIy8d(wtQ4j%bNHp310Vz;i6gu_ zFmbPALv9a(<_xwG>n-6r1h{-e*$)XyR#rCdHa$^lGM%jTE##F@63Y_`Oamw-vxqK} zfYxD?_#Z_?+7k-#6~m;w0s;R6BKL1emx7;RDLpYQYCyj|kMcCv;OJnV);FHDS8}AN zB3j}MC9>jRREXM*SYfsHNB7?+K)@iZRe;lkozKrcdltK968J5iT7*(U^@T21ye8i}?~78X}yWva{J_!ofmZ#4(SIj2s#o z0<_6t3%(r~SddH-RjPeaf=UzaSTmQzFz)Si1E`=-+c_r|oEK1bq;9#}SFzPLLM^i{ zwiuOG{QJ!qr2!&G^~X2afk%%IB}RP2nKN*x1?=P#=cQ?1q>Cjch+^RU-o!fehi7$o zwj9M&Wf&!=o$wEwE?+Dl1u=%Oi}o@;EYIlNbI$Z~zAKrTKc$ai+tRl=>fg$|02!R<(4st_miFIo= zv*+deu$ZgItR02TO`l$tJVNzT7qW7(P|5?0X?HX1fgj@8X8e5EBxk-LJ=0uJ^s8*3 zg14_P&doDlO;Dh5$DbXt`G{A44>1Pq07fb@ggKYCPmkHyvaM>Tpl8671;+wCHKSYL zyHdMNX3#R`15_qTT?r@Q|O&!A<%+}Peu z;)?_?IlhMHH!3`Zu&{*3$<_STH8nwjft2HCg&FLLg(6jNkLv~G)}VdkU}xvcW9xkI z=#iSPuCQ+c@d@GSL!~|zZ za=vx21~C@}1hxy?TiHWt4G74p!wS(Fgj4CG_QXQcqZjMXo_zsh+mb#R`N1t4@ys!X z+;7otmf1QmP>Y~~!JPK0RUZI906XPO-5b(m&)QN^d8KBy?O*u}O|HNj$juSR12uSw zYXkHF^@q~7sCpfr9=YLoKFChiC~Y&2PU9=FO)4!dg%frBg^Uabq}0+(xzZO~HsY3p zjH6m=V+n1RGsXz`Co@p0Xrqg*v%E*0U&Zygu090?g%K4^dta`bJqrE_3eD>S0s|d|#JJ)r z&UMi+lk$v>`i&9Svb7;(e*Wudgz<(Zd}KUg&uZ+F=hjxUD~c`38hf1k0^7Vr0BBoM zSUQS4`|PR@aQaDVd+T+32gG&P{vrztF&yL+H7v&milN^3#ld zLRJYmc5!8rO7udJFm}-LJ>#|%pxG^LpIhWQ&#j~%n*6t)n0d~)V=wX<7#RMhud>&M z9z=aGjFT3Ou*b;2;Cj9}45TYP)qKqPm|0mzpFuQp?E9<3S8D;$KL*?fOXNVQ^dZ8= zx4B4cZOBy%$!jQ+cuYBlff_1w1b@bLbM0>GT7az=n)~B{*wHD<%Nx}P(#-4w^@cL* zvd5$b8Qy_C!e7kU+nMDZO}3yq0)ocP&K@nnAsY(91Q6GJ-2itdC*e!ReE|q+3A(WO zbs7cifqvHfE-InklVvL!p?i&yKI|yYoQKh^;xL-=U|^=%C#Q{zo2)1fuBvKkc1k;T zyzm!EXGq>LTf> zRjm;*Q>_UB5n!b4M9^wpxi!LziejyC01L#|hERWAF}L);Uv$2fDFMD|PPVqTFY7HZ zXdu~BdRhg{+{k=7ER%eEd__lhd;j$Ih~2K^-9=YEY)iL!7g%<|zq*f!?ttfSK!v1XBIw6VwM1IP#dEzyt<5yKdeH`y31ZJ4kCNG91s-dOk))&l5! zv~k*awaTpXs#tnEhDQh>svXxYqy!sTPpO%|%3@n&w=yRrM@JLV$S&bWk7_Fn6j!5w z<9XVx<-cOZtdWVwSIAkE7>PF>tnrQgFq;J!SLP=UXmp4nR(79l(;o>wSA7o#K zzVr@)YFofBTTIG#z55z)8XFIX;OaxRIY9k6p429#lnnJ=-l5}^r4hE?5`9J-%}8x# zdO9++@Aoq`}8Au6w_X7K6RHsqr9nvW(uBJ*NN*E|39Fj@e(xwJW z)8$iQrtdEoah;*Ka}BajnxlV|E>JY|d2?*lo`>+HjY(LI324gp6O?JT8s;Cw3{S3T z>4d3st+XvdA1Lmg-b@J&+P;0%)2zIO`-e`hw})jWUtU*O!OB9p1nzC@GxAG&x<$W# zeslbGVL(uc?SJ{Rd^{}sr8#gzVm0eJkRO~3RzJp}0oovq8Zas4;3KSPb zx2ipl*dK`BHU;VtXB+8fpZ*UPfRl`5AJ^v^;r>zd+r|3&bv;qcO9&jmr|E8q8y<7^ zGV{E27l|=p9@~DKxo*+d#4z6hMcyqF=Cd4v=Wmw@3vA#|yd_39YjrcYg7h1KiF>2;&l}8UPsO< zSh=~3YP|aZH**<}-g0Nfws_NW?K39Mo+)Cxk){R>lDO`|l z7}1qJhc`2_R+7Nv`1m})wn7WsFY~*kf>lMdOWDSBk^{$te{DG_+x84eOzyr2<-4G$M17>k1w~bL^qD=NwOyQr@H3M*zQKO2%(DvP_*h zyA?#Ohu=NPj{vx!sN91XQ>RDwu$x!b96C#}Psm3ybgIKpEuf6K2eD`IEa@9MBH;|o zXxoGhY#sq_*z9E{zZWuW5?7aImzjo3)*QDmXXTd5gK#0xvZ}?5$eXNKC@0q99+kS} zUIE{12Ceh3f-Wjg?;|K*Nqb#iTzqx4I=v5|$jOo}QadRRY%sA^dpJcU2a^V#@JVSa zN+FxY)m$<-YMwfBYPRB1!!(0d`G7kA6r+IonuqIU2T%i`9cA@l)Lt)^bkw$AG0s@; z>SWt40a2a!$2-=G_1#9ti($llE`=+1qQ6Zo?}*q&Kp789u9=Z&t+s~0V$ZTa_rsXp=aePgri$>A<1`a-)q_&p#pf7=+vNQ6ck%&KHvCNNYD){M}83GP)xx0w-KK1cqAL~L{_uWISr|R`S zYfV|_Qz6DAjGw_XG4%%(SX!$S6>NgMhN6e7YeBq1(JsvGxX*mg$liwvDWMSE&&YGL zzZL}(q}g44KZQ!P2+D{-{6HFmlP3V34MRYy+XNJLo!v6v8XvhScbP2p=W;(c6EF4! zF6)+lE~S&5lj=8?Xyd78rRwPfFWq=lX{TQ%_R7;WsRhu8e1`_@i}HsiqwbAf8|Q?~ z@8r(itjm5b*YQ_hCYX+ z>&nZ^i;H)UEXnbvLr`SdTj1rY+T!;|T0~o+L0jq1uzq{wZBV!;5idw1wPeFEdK5N!pk;^=ERbl0y5ivxO0&=W1i|3EPogZIo7G&HDCEvYjO z`ozj{8X7j()_8Ige=}jY;Qq+x&z0{jHUXV`h&IxqIRVr*HnzfhM1h*7#bL%ZySZ!k z@B#(mduBk9d^YgZ_3$WxRmdN}fcDKuo!L}#?LrE9rqmd0-c~Z19BIc3#{)oCfB8;+ zk$G$j%L$Xxuo&_TGvP*SDM!{VDk_3BU^;O>lTa1l0cYSDnUAKyPb zl=ywV6nq~V9gTS$J3x~KS-^b*YV5W@V15Y$SsTV&8VOG`Iq`a zVEQc%P_-^Y2MMrgBmQG!g9icMia)?{8buaOw4R=xva&J`4a}TXRc(kPAO>7eP5>_l z6T4Y8h%dTs8f|5i_=}dy#Wh8;$8XlCbq5?bG=$AP;_%+)HEBOhfY5xYpffD+3$MY1 z>q6O|HqdfTV%BxaaatvY4A+P{!pdh9_IpiH*Lo*r7S&Yut8 zWz^6Ht<0Y*g^w0aDlb>EjU}{TSVW?%Y(@L2L7ZLsX}1jtg_u(#jQs^>Cs@73f#fTN zd0c`uMJ5g7V3P$^z`Ze*l?R*~iYk2e?K@Z7(Y)ZG@b^>W-S_VYS!cx`G_yof%0D|N z$5IK<7^!IDO)&LczGjH8b5Ike`sPHkz|A15eG~%`W88>wO2(_R4%6rjC2C+mo zl$ZN}0Lg#*)s8x)3ko1y{RWA~Uk&T@E`PgOQ-ggT184?8LRBu6gB@rySLBWnV1Rr- zW(b8OC-WJ-n?iqn&jkhs)&-3ouSb}cf*5lKka;b3P+W)ce|SnlLYjdRvOdI|Rv4MI zJ_EJat?VQ6Wj}hEm^gyOd)2>-B?H)C6bx&Tvd>Tzf@7h4)E*;rY91!>Cn`a*>6W~U@kWxE zW|W7VchFF8k2{HYw&Pug89i~6nX3@TVkeIU)!1^IBR$^}0KL>~Fyo$;J8Y=st-$vo zy@a=aY>r{X5&(nY)J}q0Uu(zQP4Q-m1%j42HfP}fVv})u%+6SC z?6*0i#b!t5ZNlus(?VaRCMGa0(~iYXR%73Q22;#?RECH#@-xh)F)4o|BkdCkdn@4W zyYOgU9e%@>5Au-BIoFIVT&s`T^ym%pr$^#7+FnFw2R^a>z zh(VU!K)SYZ_~XZYD;PJ@=PPoqO_xai0SaquT%0s>*{W%?NZ}l`Y*@j{zhzzXiOVVl z&kD{FK+9<>JibEsrh*pLE+lX~4cgSW$)O8iw907s9@jt(A3p}V2C3f_yY9=nQFNa> zckaAx{uMbz?l(~-3_8bpuB1PHN?uPW5G^c7ok~4@PS-Sj`xG6S=>2z6+o3TuHBY>m zn>84B{J3HGd>0tK6H*#Xl(N+%mK+v&kn~QN-F5vpnD?wh<3}5-Uq)GV2lf&EptBu> zAckld!-+TI=9X?4aZI?Q;n%kpxZSSGE%C=GGDSw-k#|5hbmu00^bZmQFoxoK56iI4IU;%DX@Ryek7#KFW7|9D5_zk9*aDv71;hSl6+>!>I5#fZ4BDWpK4%zyIfQo`u z!V?r!<&2zSt5xk;p6BAD;fOQ64{Rs{jCm5D;9yVqu(rzscrdjbI+>7AhVG77CE{r$ zMQt`RHGWF?1ibW)0yBmnD)bzYIvJc2cq5*~$;)(`CkYbJZ6MyHSc+pGPviSk!=;1| z(NB$9LCUcBQgeNtjn5wR7SJ|Htg})U%WIuzmlB8Ejdw1L9jQ#SLR=>4M`mgP_g=MD+Eglr!j`uL)xV~qzg0=^OoFIUYmjhH7-kM zmSr&zqWnvvFwL0fWMjj%OIzF`Bbg|0zh&`x1lbJrxgn|}$E9*uW|M}_oxi1gqc zf}sy>_6DOtVQPW4*-j&G@3QP=GUP)m;a!$Fjj_zUW3{wt*K^V408s9SVdW(5yS@999)YZYk!S16yU|@`_!mwn4dwD?kzl6n(nCta9 z^)=&pnAkytNMwloo~r?Z6=dhdiQs2#C=vWvWe2L11~`9j@}05bxM0< z_QskZM0`Uq_LlVW@=6SE`lo=hZ0mVhOAX$UAZjdaN8glQdDOJHh+l(ZL$OKTeM!y6 z@3PG+O{dsf=5M~Sb8^|u$yB}$Q$V0Q!iz*( z4z3L5dCuUgf;X@TWLo1HWEq^+VsCk477>ulKcyL>3epQ4ClhK-Y%_p-l@M!z=P|4@ z#+Tw;pg;EDbR|aBN&WR$AvdOpIWsZ3d}yAPDxuF3W$HAC8D-pS`t_!{q>tYqxJHB7 zQjdw|)a?Qdymv4=-{UW|<`s~2@nhohhm=Y+QY8&B7|@@kXvH~glIgmV9=w;->Q;}F zr?~3M9rINnv|a?PglzMw+Q$K-OW=gH$hMvwPR7nkd-2WlFeDl-!a2PS$I{7A$uW-D zPQ5=hrzKxbu4?DIAQE@VO!%_JnWIid7L@)JvzYUyj71`nYk9c2Pbi;#LjOpm)OMer zACPoXM`K5aWxat3N{%_0iz>j`MOZ-adT7HHO(sjq7p z6j8#%kT|dejRIQ-w|m_&sF)=(DKJe0P0{>Lbr-i>sAb&a(S5%cKBzmg%ACmFGxO<{ zzPAo-?T#iej(c7(44Tje9d!Go`-lICl)GHOMDhP&cDETEIK3UFvG6L`1+Hkpe(XfB zIlKB1hzGeR26nXmRc%pqh?j6|F+}NZ@YAx~kw{&_Ndz&&*}cp}u@FH#Ipid_E2JVZ2u?mG_FRX(PMpiRlz$hGH6h*N;BL1)nX(yk8PA&3 z!<$Q5qrVqRAH869IH*gf*JpF{;PE)1MBZh>>FMdB?(~t0bPs}&`0$_-RRR*EL_e7E z8AJCXgZt%R@CzPx*y zdP0S*93>*@qGN@)dtU8nZrDSObdzNths3e)zn_FUUI(*2*M~zzv78!+v9qCi6}~ zErkVoqzn;*@LCk@a+|Me>O9VUzA$`ZXxc(zGQJ{aTb9fwVefUJz2E(m_b<1*UYp@U z9rLt}P~u8^_UfYBwr96q}zc5Ji%{=<9UL?)!o-r6D$-bfl>Z0*q4nB3~@ z%(1DpL_5*{I8*69PJZ>eHkx4W@LcxW+WgU~+d=R6)MVw^3-==|x*|5w>JC_3EEkiy z;(PJWFPw4Albs%H$GJt{+S}4r>w{t}2x8MlqBY&Fj8*Ved;0*`P5T0yEWTIOQUZ1q z&nrjT;d@VoD=pZC&lnAVVYlp3Ssv#-Sgm9pBo`W~h^Z-6XJ|jzO+?XZsm;FU=FzXx z&O2UdXrCH%d=&oG$LM78mXPN%PTOu zNa>`O7mW68OdY%}y#=KiETU_3o;IUg5=m`dXFWR$1S^?TJC5%;ie*3c2VM8?zY=KHdTX!GaTHW=<9ReNFppXtZBd$I)9b;$ zhphwm4INt~C+|JH%e+B7Vp>{v=3R!-@Q=lvvoh1kxFdOL>*m+0%2;NohcC*C`?=ee zec{=3|%(uCr6{j2G@xpi=3Sehv`Ca4((DA}4-3~yy7sFUk{qHa0`u&?&r z8Ne8p!LA1y=6bKKH2cuGU-tB??>ve2M@&8n*N+&#P~LB%-?hiP;@pMLb>F}IPNjFz zx-eB%Ipguz^~-|kz=02viAtP$>-JI}X;g1s!76s$I`7!M-}{U6+d9Ix=SOclrzTre zq>~rEF5>iQy)X8mAMXcsW;8ustE)O$x$ep8bK%;*Uo?}F^SOU*3GVCp*)W%|PG>fC ziTS&8h`#6O?y2xYd#bi;*0wKMf1b=tT9t9ke!9E~Eh>kAvfN7; zAyW^WNA8V)|DM1}8@d4;a#*)=ysJ2VXnb^YOOc`{@{QB@P{{|kFBq( z!#Xn;tZtTkmyG8iiv_*M=<8LyLTkyUk!wd1!{ry$2K+tBq zY-t(AaYp{_cRJ;RB|8i#lQcn^LgK#rcY#*li@-vnn}B{qe%V_zK*W4VFAPluGOA*S z)qS*&{qmt8L4xVgRj0@&D!Hvf7Qk$=qXle+kipmC7kL`88N9SIRHLYGv06~Tss=V~ zb2LfEix?`Rx!-VtaL2@@ttAtfgNW`x_5!QViaY*68h7SYsiv>U;iTl+uc{iw^*P_% zQ#LMl(XJfVEA@(c9kKZPsMlW4nGFrm$C}cw-!$~uq5U=4fcZ>HeXLjYjSD$B-2;z9 zO| z)62FlQphA^7PZIh>%WD;`kQQ zul`oE=<@yEXHC!YnM|IQZGIX0EAjNFO@f=*^`&dnE(Glx5D^rKVfnu4z5ZdPia`12 zg0Sd~r|+PfyoYpUI6RgRVyv!bV@}f%$@()2wB&Mi<+zWdM(k#svjtWGBET5{JIi*E zZiIf_le`bB@?6$zybSv;^d~dlzr&JX#WLS%>=#YQ&6N;`RRW?ZUlZbK%sAv~w*ZBJ z=a4xo?KPy5e264IzPXX%_;^9dOPokBHXG{zg{)suR6&1@E{Ri|C~%TkH(+ZP1SxSB zWyss4)C1c8%(%N4h9a9%Th}jVvEt%;bLVj7L6Ue0tK%>@5H3gOvZkY2V`wV$1)@eZ zKVZrs<(2TrfGT(Gco_-2Z^p6G{pKY~NwI?QjfI&^%^NXz5)ilrmLY(8etVKIW;OOK zmdm!7Y%G*4+&9l&PCCOYN@eRRvEtC)aykybTbWc^`o}#Xn z@1pOM#J$T*Zbc?uE_vhe@NIjUw-`r8Sy^`B<#jV&*VhHTXOv5xZugd6X>>8NF<|V> zla%FAHP*U&-~asRM~YS(9IgK}|Da{-o6F+6ip*D92vmMDd7X4r87bK@L`tnXd@ZwQjp!(UEZNj( ztKct>+4u5%l6@Q5EV(E?uDGkB$1_ahu;ly~T@I#NFtwIVF50gcHO#}|GA_!Vbi0sl zuC>R0!{_BPGQpSjp<>4WRo0NUHC>h|6S0V0vYnMoDacFM+0=*u){1Xyo=L4>y9Fqq zlg#Cq2r`kpXKtJI)RWMWuM2vmW{CmBJPA zMBgGQ_ayI>Bwx;pSKAk7M}FNu{qcCC#a@nAN(F%n*4d|;^d0NGzSuto!)k>9Eu8%E zg6PMM4Ib@j#xgEg%gcU`qm)vBl!7)J<|RwYUXRYa9Uhi0Rrw=s8`^orrkUcvs8tJ2 zra=z$SGMPL?ZorruNdJbyZV@3Cm&^~>p1q~tx%9zEV0ZQQZa^~F7r~dYm?#H#&Owf z9y}y6aZ~yMiy&86AAEKlRW|xe*q*w(y6$r!OK>>-M10_VU_LF}Ho6a@Cij3&&gq+vCF*lwG$YPV^R!y?QbCRp?w7FHByf;AADIfkFx221d~J|zFv+x7(kojmZpMO zDl4%Pme07UV9v-3c8t6Rh;x-Y?|cIduvJFX)Cq++laRMoQeaQfdJd9EXKy&>|LxV# zs^2_t|I^LXW+@Hvq)pw}Oiv)66}s%pgg`I6?QJWscMM3)IOt<>wrJ}AoQBAguAYT! zB<9C9zBzh&)Oo|T_ak>QZoauc_aW6g%3Q(t=HRP)Dh3G6rI}?cz;4%11ajG*AR{(`$vt9Yq=qz~0B-SF5!y>R` zegzwHp8I|F*)_4Vk?!bDjA+`FweuxRI7w$gJAhHoJaD_L zQ0vizPb(jLGyY`U48yd7;^vE){-(ZBFGt_Lg+y|bXK>=NJgoP8L^|^wlDW*>hgBXO z43;Ld)v)m~IP}iOGOx88=3%^aG1il21${&P(dUh%zjgr5HhO+Tw8u7zfmtr}0OgB{ zFZ|Tng^Y|WGP7>I3yitB#M`!ZpM>9|>Xw%47Qs7G{LK3QAHLo@9_zjhAGi0oY(n;o zj3`;zE1MF^iXsi9lq7q{MMbIXj24v&sqCbMC<;*&l8`bI-{X_}zMt>+_s8#ky`I^w;9kG~p3YYv9nC9Y)nUJCbiV&Kzjb0C zcd3g;W90yC%F5-kTYlb8AIEdEG9+q;Z}>&aef?eS>&~6Q(YtpFE6}OGDx3dJ7xO^N zb-UapO266#lGe(tBO}iNTLga=bTS@Tj4xz4aILD>_0Qvz>-**mnI8Xab(b!0Y`VE% zWtEaPU{*)Iex=$x;^t+mPFgV9Ki*B|NCv8Tx|3>)+>5 zpOmy!cFcgf39HK0toGwgqfe52`rqk&(BGonf1|b-6H^kkzkA^BOYWyUM!r3Qp>;D? z()EBkRVVuG#eNi^Ck`d}lk_-DUGD8a{@tAjTGnp9RgTfi>6bW7w9^ zDfo3Wn9D7^fo=6MgRVM3O$7y(cWvORD+>jpQ$@?LE;-niWyI_q3dy>sAdz>FbuycZ zSSZ*2X~5X#0&lY+lQZ&HIDg-u0^|;NO<;0K<#@3PaMEqK-3y4TteR+o!bhjtPazXM zVljuiK5|X2u>u?0(!;Fij?UW9>}2aV!Y9=8x2`q)x?(vQaC?LBht02QxRidDRR3;x zAegpga%5@IaK7j+`{8QmKkB8vuR?p-+h+a#+a%$>{ zl_lS|)U5n?r@SDV$^eFheiG{ZI_#< z`qh)nbw8LvNTr5vx=G{xg~IwPvy3f*QyZT|L`tSr%`Pf6tT6XoL9qG=P6p#odG|L! zEZZn?u&;{as6xS3Mr_yD>{9r-?3E}{-6=L5mFi=8iTSrzed&7?cvRUmH`$sh$RfFy zajckp;5m7MWgUE47;R#VvUo0oUo)4q&AKYtD3{kTxI%%n_VQj&Q4b1sox`_o3wBDj z?BtlnYwUHpS~6rFRP02X`9i^56W;7VIDXm-^$hVZ@rnC`f&nL|8yuq8k$E|{;aHgV z;LL%5ZX1n?**v#vWe*QkWB(f9!Jm)wBk6Gutwg@;52d_& zvg)cC9Sn?qLR6GFiAe?drwfkyn<+vvIenFJ{G7u02IsuObq6m$sDjyNA=(ZcLUGbk zNvAoJE=XguR(~fP4^8_*C-(8m27=YuUTi1PMVWl_q_xi_;k6G^R zp{(af?^x7+D|Djza}P7($F`hv5i`(ye{qr4#AM&v65rVux%aOtrg&<{#H@S>j~KN* zG)(KT+dSsG?x(m36AFoMVc)l~Z|8Fh{5@}qcr%B>sn(veSt6lg^5KI??8}?qWuIhN zT5)~QlJFzx!Ox;~8SDElDKttH4lI=Pzvh}fjKJvgO<25QoO`pZE-Fe<*go!NWq=`{ zW#Dt`6`;TT8ud=M1UA!ELRb|Y>02t_&Vk|{lchEAsp3t$Q!kcgK#e39Bp;x&7uJ#L zV^N+8{WSqKyz8vz_Uk+B;O5Q6b%xkw>DTtDn5Bx9Vn)oPJ_Ds8O4Z#1?|FA=1ye}& zhAKc$#j=&hiq+YAQ-;QRra9!*(6_BxS(I5Ee<=4mJdktetV$k^E zHL+3`3cGjQGRm^qX{5HNHrb)lm2RZ#bq3W=tDPg*rX@4JYo+CLI;p5ucfeyXw*|ih z!Ctd|k{LbTVRO zWi_7kx>yT=+F(xnu81v>Sch4{wFWTId>NKS?WO@2^WzcVz$YnwavunEuVLb+Kwc>ad&teDP3TMQJm`h@SILY0(Uec{3VvWh}MMjh31^WZ?!9emGT(eK-yl~jMiD@>h2;~2N9*dWA~i$k{?#bUf7ex z8C4f|rrhlj`-yq+(fS{QPLJ}xran$d=d3m@KI9RTsh$7&wb_k>vU&&GQ`a-FC2zkb z$TU86`@PvI&tUN`)&pJRabi2p3v7OWu|IST|A8Hk{75^l+6s8sDt6F@N>AS$>SnK@ z0hFUWpnN_hhtr#lpPW&9oYF+pBkg!-XpZj5HJO{A?*f(LeA8%d@I;T@b@@MNdOSbZ z^S2yRH@V?S-@rw;R?~w&yTx_wZad|v_PvD5dDOArpSVsko^KOBX~!}v(EdUzc$ECI zDzvS9cGAOBydGrCN2gZSs?sMVEqem<_Sn+6Bi4ZCIIW2WT?@&QC2j0E^VohA>C7L% zK|FWC6rR~##Y6gYPr;K|gQO$%<6#{fD8B1!)NHpk8Bv@azW*WIa6^N<$+1f1ntkua z@|5UD7^o=M@cNj1DilfXZ0IuW#wG{(zRUV213bX5R zxbW%XJNtcQd%jc*cwQ@(vTRVgW;aq!fGeQlG-aNiW7O)yS%;mcr-R`r4s9@2xYb z`d+mL86ww@{i=_=#W1T3QMyu4d`1){rMCTa&o_`L>GaexUYwQV%E`~5)YIp4bsUUE zWYZ}In<_|yrJvT^y}h4aGwS^QMAd72?*>OCEn@G}((InrZ7J-PWxV+G(-qm&hGs62 zSE04PVjkPNwzC_WHwmnpKk_I=_D0WlVI9U8Bg%koh+2}Yql+|yGdFBx6mw_O&$nZD zr~A_C{d4w6z>b(=os~CR41OE!$PiU{krL#6JA7W8-%63=VO?shZ3a-iQVIx|?UxA2 zOv@p{R5oM|qYO$}Ei7_o!<6k$zhn#*R{rKOn#!+YFcCtLi~7_^DZ$I(d8E-kR#*Jx zn9(N2=p}=5b!Lo zER}hZ^YYeJ0A`e0zBE7bi>hi%oMf%Zs_=--XZGj4%$0H^|2369&0W$%QC7G&u&GnN zQFwl$!>{SQwu_~jC@1`np}kDk?;nO zf8;C3s0%KS776@|1*DeBg?<)SuZ#uU|K1(c4N=LkiQdlbRFL$i=L#)Y@rs0?S|GZIJy6oQYS(^06 zJ6Jj7-liX697}DREX70hWh^YIt6}{J;w1kQUfGKQiMt-2eeEiF+>-XBU{C4j1(tOE zczPWXl@;!|Yy6pfdGDpS8)~0g-g)7$*e}aiby9O84N>ICc>>ErEv;Di`S_OhDh>9(Pvq_#l%(^gDTzV$)P1b0dY*GagIkDz!&4 zS#|VSRG7}`A7i2q%`cViVy()jm368HIi)~J9y0x!<;;$Q=Cnn}KR*|cWKg+=&2&cC zE3?4p8a-79n**uLzM55&C~my8df&QAxJ2C3Mvit)+fstho*bnAzRMAd*(AS8aP52o!bzQWOro~mLVdL6zul0;A;!Ot)`PbLE zQrdLWGV>C;Rfk2KraFU3`a9*;LzXa&ibNdGxrLbV9-2 zy#1k9W#uwz<2RfY?qIA-Hg&d&o=je5%w5zs7cG#W4G9U6ole?vdl~Q$UIJf=o3WDR zosLax9XrYKgv;1dlZ=o<+m7zx>3H3L^fkDQMsD*l57`rB$uBk@;=L0=E*&Jd*0r~e zo^N_}=XZvRdM5Y{*Kb&UyKZIBQ1I%*59Tz>`&%9CiHs7gZbMI;C@hT1dJy_2mdb5X zSwG(gdUpG7X^~%%`a^w^XBPG)yegD5263TpPC7a|VnL$b8FPCIC$z-+{d;ztR90%P zIDK^Ix0$@d3H1Ri)$3$>{V5u6V{B+U__d)SW+^`v#j1g9e zfIXZzuWq!jAt555I8%Ax(aGd;w6$8E;;4%a);pVmJP>6u;S7=YC-8Wt2z|J6hhj+SR85dpZxF%ybJZyy)X|T-N zE)sUl&XhHt;#T{ixNHr8%VFvzIIV?#m2WrHw<0e4ItOAW{se+%S5gMfXi%Q3pT#5~N;v zT=^Ymy#V0}deOUWIJS4NIbu#+Q_X^x6hSy{>DXjIFMqgX0ZM-2!PO~q^F znAAw*J)Xd-Spxwpg$l=_4F@9><8Sf}jFD(TH$907Yu4L?&TzSXV3Ok~?sxo0rbAKBBvum|g|@HBK38S3bdJsROA z+pskI+GgIUH>R>kcZY4nq%U-H$_yo=+@ry8>wQJD!P2&#}C}qR1a=7P2rE+B5v-s_7QePD&@`;o9T4DTv+$X zb9RV!2+~R`nP_*Ai?oyn4h~MTKV_z)`M4|9lc6GBEcs(%N(iT0sirAE4M_tjVUh8o zIr{cq^}cj5)V2EE1`1($g9Vz$!i{CZo~gD{RxxF~xg|Xv#mBf0PmIK6(|Vw3uiM(j z!L$m^NgGYoJ81SxU6eE!xT}4G?W;(~h-E52p+<=|=h}U?dyGt1=$zy=|4go!fTaI} z_PaY=eiA3g^PKVy#7gt=Kex>kY-+~M^O#NYTgcGfB2uhi`3MWw#=Kb9vCTx6D_vO; zK~|u1#NLVa0b7n&C3U8ZH&yLx7@a87NWFZ^U8sa?JwCy(ymI76I7o$zGI*sbT6%Rf zb_h7_^5}Wxt0q<302_sLEqkuaB1xqKab-&PcAJ)PywPyv@1pwT38q`4M%d2d^})I7 z{+TnsO9{BrKEWRjt+#qjabkkh)#5&u z&Ql@9Z`TW&ba*^X4pbdZ$Sz2u7pCcsp%D${>f1n4YOi-Vn*3UC@3W@v3|sm@YDZ`sZd{+`N9Zf;7;pvZ{CU>qW`1>^Yq-b3V$KS4BR@ zHiOfN`g|2hsi|B4c15nIqT#%)^+*cZgtr&t)RXTu1la8~xo+(-XTaFG!=f;q?GX-C zK_6TC=<9<+LzJ{edyh6yy)Z@)M73UBbelyFs z>8Wa;{l$S%s0DlXe*`0Dn(?b&oRA6p-|`W6HT)a_?Zv-3Ydt? z?y9LgO9KvHf)PaH5*!A)!vCpL-PZ% z*Y!|?tbVBbdRRbYa2kVXaNxj!Wr$je-cbygukSxb7-$Dd=a5pXPZaS2gFn>Y+jkFZZDR} zpxla=!6^hQOCnJdv_GDxR(uTp64oa;U$PXOscuo*K|Q6|U<1-|%wstH!0f+kMBjd% z$fAKyCqef|&<}dPe|YApxBg~HB2EE|uPm^AiBwh)IOiL=n2fP*2X6~kXBXx^ghsRG zz#;SJ+??q=YOq{=#El!@F!+EnO&GB-kYG{~cPx?u0QsTrt2{zekemo8d+6b6u?cB_ z-brI)#&2d@6j3y|0gMZ~*M89UW|V0Klem6n#mvN8;QM4Sjw`=95=T&4e8 zw$MmhaXg<_=4~!+ya6r@^pO*tSCZ4yJHQhGVbm2QO(?5QpEd?|d&tl4II0tVkI<`E|QRx~oGm{L#AXrUnGThnvK%@bV|huc}Jg(H1c zfm4^1J)<}?NEti-_tGpv_CpxT5Lu{OR8>3c>-87Lni9Dh(&6Via;;|@jIGfS?6+uz zr^nzO@R_~##ETL>AFM;MmjZDoaVUIMN|53 zqC=o@68uwBtS`XrhmZN)M)ZY4cQC)rtEs9+u~3fbx00f;qS!i9c8hjf-@_ApWfx$% z(%Wl3(^7yz1(7OOIk&nNF)%Rb9m8K)g=aId7O{g$90vCP1tyV$3EeSnsPslI7_8nt z8i5XV=rGPRa7o{RTXW^g2tF)7P?i$!5SOrU|8?gLX8eHUA)9Ey#2{vK3APhUgolQB zI%>Z+Y^`*m2ygm=t0Snsuju6{jG@Gr;EGd=b$S)F9eE|gE4#mI*A-}fyt`#KRn(Z) zu|l+K!?Jk;Pte%ly3=fN^L zHwI%$XP5%fB;)HZ&d)>JcXxlU{f0VdKg8T%J4}#h@yD?91^?Pu9OuWD!=F=-^$YSZ z^p^QMTVI$GFt4DXD=6qqQK|)>-)n{){TB<+@TiLbV_~zFmW1%xz32`}`ju@Gja!4h zyhKr+0L79)?0Z~#=q!hrGwr5L_kma^vs>8UCBbqE+VeEazEHmFNR*B#3^Y1jnx)`p00>bKSB1tAfy!s|{e66Z`( zW(iB~rbBMk>p$NRHC?}3td|i6K>}?5WOIwfc+<0R`>M_L_uM-msBo*UPH$U3Md)2R zGk%8RuW;{FnvI;IyDBI*V#Z*;?td5dJa(sR1OyU;RUoc!R?|AT&lJ$9r8YG+oj-pb@BUFQ{B>j-A*df%j-AiWc9CmBoSd;S zBR-oBe-WAe^qDhf#AGVD@C(CdKAtu(Fo;^(=kK4a+lVy`4Sv?f!L{)9(nv{30lk|? zSoj5{0Df;w5nGEv`(C|QV*T`aoCd8WbogqzLXacz$J?3i`THg9DNoYP3grbd5PumF z^~fFr^C38{{gqRgGvkynQ8GZ;Jx)B43#1*ct}@cnL6daE73yTFA>lhh0FN(hb`{6q z@Iwikn2|?<#5raz0Z7nSmHC)JanUXVaJ@KTkZ|C14UQ5ld#moY%_8l)zsFaluw$p$G@6uBky{*2)br;A%f$rVJU_F8&lqcFW7lVYLSg7F@@h zi*S7*9F$=Bq!$$`v1eXbWz#04UpN{WHNjncs=KX?h#lRaXKQN5&GjZtI*`+BrHuqGkO3h)80Nq zRD>PE!@n1itYCw;8~;2>5jfK}b_838TlelQ!sy?V8d4YP{OWhwYW0j0khkk{UnlA4y*wlmyA{PaAtVMk|mERg6ZUBtd z3JV|b^JCoR1)4CHW9S{oPEec%5V6c`JdMwvD~O5dpH8^g3B%-3Hh7ZpCh>P5jO?sX zJ+{jlaI1hvu6hMlH2c&J_G!Fu$vcXWZX8BUPQy8uE(!7R(a*t`^5dsZ7%P)*$Hv5H zXlRJ`0RK*}5*1;@+qe3ay$_(Sd2Ve?P=xbq@#BjZUExybafP|rAnpcK2!wT9+qH_M zA?jo&R`!d%ZEaW4e`0s%sN*?+@+I<1`MP_`l>e2qIx4HwXg6`#<)wEyy3VVHR*aNQ7Rf%BSN)ytZQjxc+i$5a z;84fIlxhi+%Lp6lP>4Q|}%3%2PRbqj7BS|QI5Z;e=ao~zF&P)^U7#{jYy+b^^Y=X@@ z(z_@6IT2du@x?=dud!A+vhs7?nK^w>OFWJ@e7u3&5ERZBuZ`>isx&6*leBAFVQn!z zGt-u(Br>sr9-~nxR#6A%2WovxN@{8jd_pJD_&ppRBzhQ|%bHSLugc!$$MlH^!Fn7Wgvv~WZh#N?O3(d6B1?8faJ6jU zdPA525t5p2ih78cNGxyEIgONGeAK~5;?+c8P%B4be0)5!&$d=*P;BM6$KVkT5o^?5 z2qC=Eh0XsUwNizV>V(qQs`aTgl!rxq8pYxwIzxU@`4Oi6ZnZPs@^M}aTjEleSO6K z-XsX$2VZOxWFC(pz6948EkXBbqKdS|ijhQ#sI{L)>o02r4V$6eKs59h*v!w4IXD(! z7f#Y3zXV|^b*&E53n~kyi3K!!{=A1ktR}C8o{LV=aQ!0+Xcbu*7Kg zr=n+4u&0=7#Q}3pF)BJ*{RmBhTzk&)pE>vZQf1q`qAg8)eRE*kwIy!gROfIcSaS1} z3A5r)HmH@v)2w5_i-0B;N9?Zp2sflMw(rGaz8CG3N}K7CXdKYmG*hy5)I-$<$SU*P z&pZ=8h2-kXjPz@p4KB!u>g3b5KBX1puJo#3gqWg)3%Z^bN077Q>GeSuU*W}oOsg*+UTAwM8pMPJ$zy{F+Yfj6JxU!) z*d%2HOwM3RgHf#W_qC-+c|g&}lJn1li7c`2kFLu-m0TSfXRPad^4Pz8D%0fuz zj)VLGEqV8MmguQw60A0#wumJc>|0RH_1?7$-G58_OL@Y3Y~zLv4sQ<@-L$>7UCom<$rU%Kk-8~Ju8?AS16Y)fY-U<|4)kEjiwAEK9)%a%zSeJGJVVsyMKyI^rf z`08X^e)7@>qWwf%*`v=-&k%vEGxiu2^9D=z7vHOr;K!IV4ZQP}R=lG@x#KqJvZo>u^OE=DEC!lGbP z0>f*jJQ6tzPYwxcFvKU5l^*%R@&@}d)^kRoAJ>*`*siuUVbS0~y5NJhYRT4XsECBh zBUVOM!%QTE@&!>~Ab;lz>cnQ6M8T#;8_tP)PWa&1>m8}&7LnVgC$6&17jwE}3W`}G zHxW?;?ge-sLni*P(6YKgyCD1TRWC)J6AOJ~|2RqQscfFr;168ynRO;zI8xazg3EK4 zzcjv*Qcy!dfgoO2g^qX0jWQ@#KmI+bMTnC2F3nFXpUh`yeWCj^sy^(+2z$_ekvFQH zaCaqj#;+AiBO>dqjf`lxlVCJh>bk+#nDA9b*9E6&iaA0#&Vy*kMOZ1oJ)Meo9&S@{ zTcLsm@pqS~d0pKAR>Q;mH|)iTU`^X_8ZcvG70$WH<@@eKgBL|;O@Nk~+PAyg)~X$# zkIt;Lv$e5C6o(`-;?|UEjmLJ`9(%EwO|Cy3ZzsTw1BjH9tymKdTtSx8NT^lBjCY(x zTZ~^{L2viIOd=k44XmUQ4;o>~!I>R9f9Pt0=1FR8C>b$(cHTJ1MRZ9(RGyX3oIUf7 z$sm0X+_cI}OnXtSVM0`blEvg>=+LM1f_Lk7+s7aGQa>$5{cca2+FEDz_CX}`f(L)u zk8Fmg@_Ki-ZK7W!>s_(->-HMYs~eZpG%!0#^~nSC0NPd1<-Pd%by8u`@}XKDW?bx_ z&A3*l#m@fjr_bvqVjdRWou`ucF&@ReGuAcacU+3a7Ae@oPi<}QTr*gf}*YmA;)X^DU1N%QMuq*s6xw( zbP_4<_ZnAjxH)K^mTENr`ngc(TdU;iS>MTcgWJH&rGD@Z{t=ClB}AS8aPHl^$FFRA zr2yAFNXsqbpYZE38mcF*Pu?(y8F6W=9V?X-bMZaRYuhh67WWr9%&>m`{JH%WD>BKT zvd+-(hmj2qGXaMG(x@>VW&Ynd)nUo4=n zv+sH5^QNvQvaETcIpZzHX_e`8vGhQ@Kom3#Poo$d@jn*y;2yoXYIBcPuW77tbIg;N zhYVa#=~}o+MwW_Jhk2g!Osk5|`jzH${Pi8v{U`cdgzE6R!%j+X(W%yk&8se0t@)Yg z%^|{-wxv~^?IzosUvKK?qNlg5PBkmUq>CRjzOJQ%ZoK7dN%`yR2Ytzx&I&E6sX0qZ zs2es23JCBZo&bhA;jz^22ro1?ft_?aa7&oU*Q!ew#w7 ziR0&68OUt*8}6%~@;BSM^%=kw*i>$l4Q&G13N7dbGFeoW3YkXWg`rSBRxe6SWHhLG z@PL`P5ac;x#6}D8aQDU68>PiR@A`buH!9dm!t2|mZ!BqEo}L{r-Ib6i#CjR?zuvqo zIO0$V>B1dR%@BuC2?hqpJ~G|Wpvw2FDtAU|;i}YdZ4%9ML>z3EqlmXtRlpD`GaO(1 z;*6pIf0`bXEQmApfJqun+(GfbQ++3q%7-sFpvC)!S7k^={8K_&;{A%d%GzOg`(QCl z*lfUFwjBKfN=(}6)3Kd!kH56>z#1X!JtHMSJr%?r8M>#NK;cl9F^K|;y@4Ww(1rW^ zdxLay4JYD!P(Azfv z%v1k^fU+$>V^K*rYieTPA!rQaE$C5y!*)biCzRWrnOipC%S&OHEz*L51*C{ETz2n=6gsLsuG|Eu`cW7XdWpMx`E9DL&~m{mzZ_|c1tSG3wY zA)DGsL<%o8Ha5E6-6yqrsR{oW-16_jySY9MOMd$)hfB`$-tqRm`$3%zm&!h+_W z_eYH|eVz`yQ+ey`a>r1I%-h_ArKE6GnHOnkn7fHX3Zn;Z5TpZ= zH$l=Q<)901kfBM%HcEU6Hymv?dy+N0p9_ zPP(cP79+UcFK~tvR{v-3D$d7@N6z3@8D8#XTB(x}?JeYu8ddGJxl(7+unn=6kG-S7hXvZRylMnz4HMr4y$Qv%vWM0iR` ze?GMsRXLa=%X%NT=_0}7TqO1eLNr%i&Gaw{{nQ`|1|8M zJiPXBiU^kMA&Zq|;hnNzu3q1B1_4Dz_$k9H)tfLDa z{Z~|k%Kg2ZlaOTSFEg;Qt%vUpZaUe_+gq{^whGxCu!EplkN}c{KF5d`pHU6VwoCGz zNRo#8B>1@7GQsg~$k*80u+!ujW%aQ#34vX*uK6UEU@d@VDA9!^;5GI+D z(zJ5@3u(dP^N&NL-_O1pJ3h!9#(JDH`?Z8jnD!r?a~>A0A)j#+<1a?93eiy9EN&(Si1iFA>~`g0&WG;s0G_M1t&cs&Sa+|?9vaSl zV4LG=dQg`=v?J8u>y}3=jhoBQ9D3nZKj(I-Kj_{_+Ku)5w}=GD>#YmD8C5;t({CZ) z)6-*QY@ApbodD1}F){IK8epIc7cSHc(`1_g^(Hz@spe5U0sDVH~l>_$!V6C z-EzPDcos65dzf|_eoRj;JTUt85k`lQ>4GmLQ<*Y9pQ5dqMHGqL zzc%(Uh0+P&7(g?q6ZVmX6eG_*4E*Oi}?${KDAwiB}Fcj zw#zQn=Q9c6^nEp{jRp!I*YuBDkVrhhPOc4S`eF~Se1E&?=`EF&JG)}bV*PMsQ&Lvu zQaEGu&Hmm}1N+q#>`dUX@VQejo%Si04y{aESs&Cbt}ZqW-ciY7{w0_h#FvEAo(>Rm;-1ACS2<)`(wO0Q)r3z zMV0=3YF|=v>VuOL_i#C8a&W}ls;;ia5rc6IPGEAXY&eRsLWZT1Apax0Az1!p90aCh z^j7eBXD6pqY=H)BtmMwoplHGhn&k))yNtssl6bao@{X_Tvw2<}?`h7shC{l(~&h_4PR4@fg zxZURGl=kMEndv*Rru#Tt6;AOzOQ;G*gMzYgU$INYN|#=u5Ah^8tt-YMq@<13*415W@*4_5 zkEJYGJ8@}gx-~S9#A5*sHG~4NT!B3shbq>In>Qba^E(Fz2Q?i_gaIY}#4j9nM0yzp zNr2J1R5;%DB7$0y4mu^=F|1Ts%j#QUDYIUvCNST@m#5{)lM-OMIMqP#Mh-v#Ku751 z7)E^HGlNIN!ptm!n<@l_557OUupk7Bo{?5hvsA(YC)5XcRfq=WD;U6hW)b`0ynBem zB3d4@A_CkJj_$y81lTnF2u6P)lzaobeWbOjWHf+RA>Q6JDk@9BSEB8D4+tk-s?u)? z&*Em&)tfkw>f47`p5}d~A0OO!}GuV1W=V54@I(!msYbhf~nq;H`4U7G9H!GV>^U z1yOq9Op^}5S0v2Apk_P?GodP%nqa>&eYk|v+w zh$s41hqR6T-)boa(fN|OFqem$yX*mf;5HW8=z!m3p z`{LL#Ekpl+X2#AvVa+jh=#=x&&A{}%ByS(8i9WBK`icGf6|T15+HLB~dz-=xea<qMCLSHPFlPl-g9&K0~_LCIFFtQEgJ$&C+@%X+-~ z?OWoZaUt%VB3Q6N*7ORe5NoDE@W-xhTL)9Bo|S#AXxjAjA|RhQ>T-8~BEXivcAWRhP1+ z@sq%J6~(*Hg0m2@d^bbD@mbd8xpw zj)5MvajfUoZa|zPn;f0{l+ z3ctqIo>s9mYF*>dbh$c?<%aeb3sNW57+6{VfYyjM^Pcxp&M>bC4$82wFe1s`O*QUk z``vSbKX)4)#Bv!wK?8(;8}<&@9!!KGe(1NU$GF=-oUl_3lSBsr@&c!TK=uA!RqcAf z(S(`a^4gLVIdu$Qghe15*6?J0U5I7>Z z4BYI=hW7q`9Wk+?8zXYy^>p#gwsb3|*cL|)x1D>|HM^3cvn6~9tVja5l|8qew^TuG z%@HLV2HD(`zXaqTp()F^w5~tn?3R?A{9|T@lTP9sHzrB&<34Tv8{H`J=-4!sRgx29 zHrq#Q6qa!2s>*tV{oK>_!QO!k5P{-w?k3;>PpXdIS1k)|mT8 zD^2>&C-4_Zbei2e38VcJWGfqWE{o^>iv={X`3j9T6C%hUI?ZBzef?3PXG0HA zm3R?z@n;u{WWiR=Q_Ep2qfco%l8xOrYHRnkwCq8V!hEO8N#NSXI>-+*yN?lgCqlJm zol4e%y2Zsw-4z48ykU45uS356ptDRl&U3mn-Gs*os2~D$aTwq@xeH_^W;3izu|*|u z+H7gs7E-Ur-G7|*stplF&L9*@oSQl5XdU{qANuk%YlPS?Fy6IS!(Wh>1@}%U_;e6&L5uMPOnnHCfmrzEv7(Rr4l?^Tq zr)cGEW$u6`BV`k_MZ$YZ+MO2s`~E3HCSzJG7szP|7cX9P?AxNO%re~6Tp2}W*v%V5 z-cR2$2X2ITXF}}h*aOzC47__X_ed8@#~GPhSXv}lC8V8B3*!;sJ9n?q0hOq5fhWlX zG^&oqmVgoLnI-7iF`?)H>}26#6Wqw+u5vXleN*rxu%(gl@uc<3m=sh*{r2qn1%n$F z89eLrD7yT304wyEMJu$quvllQd-cj@@*R2m)JnoBo%Exkwre^=EJB=QHh3Va&CgG6 zuDP9Al0y47{@-AZR>*qGkg{QmJZ2Oa^TJ)5nLZv6y{zv42Gq@20NiCw-3lp8 zIk)1x^Qp9~$E8Wx1arxe$-)YNKPbsvsM;@Tn=l5l&^K(7+@F5bmcMK33+uINg|5UC znbA$yh7GN9l!l|JV#RNWH$N!+^+`ngSYGH=*9S;kqszsD_AEWC1u~fkoIJ&QyOUlP zcjyyvFNe3K%rN@2sRXkI@9lU6VKu`-f?keUze|guB@>hK9rZ67W?jNkv(i5EKUfS3dV8Y71hlon?0`i)t|LlMj+QaUra{JuGzhM|4wGF9fyQ?DuGIRLG zTrzofm3j7b*+awbt;08e!rl~qcbX8)qm0C=CMDdui?=p^HAXjRb)q{7d)n1s^@V2sOGKU8^6zL~w%j9bo)HmT%00akf(*Yb;1_liv*umr()({-R!mKtLpteF7#V;gu9r@@N z3>J&^2(C$tw`iaDS#KS}#ai+V`H_{$h7GtImG|yt{`N10ud}POvrgE&EgE&IgQ^w` zPk#kKn~Xmf=54@Tsf|`u?(Z<6s;Ay zT>T(R>Q&_B@8|x1DLMbopIto#Z!4k~zOtee^py+|AJ(_--n!T;LtZGV%2pXsQc@BO z=rEraDD$w>Ca^V>lr%7+Jb=6poi(z1EY{W37LC1zgcr+AM(WkT_d8}1*t8-ve9ko* z?CHb6I0zc?n0VtU3W%ZQ(QdagbZxY`LdM3GnB&EALKiSzBA4y!w{HYf%3Eo5#_P?5 zb-*usez>cEZZ$-n(MJU!xR|<}wkl9F6wPt6xSX}(uYkH+rP)hsn4k!_n)Mpxwd3<*=VbQ1(Nr8m1q z4;@719t6Whe3$n;I|U;UC)?T$*#~kg#PCwU!)#AN$$HW~XkxiZq^X&at$45`PyF*n z+#^(t7aK6o0feKD|13$H;$i5IzQ^t)#xurscF&65p5Q5dpn10*oV1Ft`vGenBB?kAcS0 zYUP#w5e7z^vJe2LWk*c02P=$&l4^-?)#-2FN!l7xK)@-7+l60k> z<517Y0vV*}SY)R-MU&`p^FtT?W9V&&qWvHRAw)wskvs)FbE{@LAxp7_Ep~N zw8)llfT$3PgJ>e&(umpuy3#l7n>NB1KYB{Ji- z9Had~agn0Bqrz6oW5}>0;<5twZo#-eXaojLjBU;2co~`}L=cl+DR#bh28IY(T{I_tj{n5@ z?U;v$sD0cpjo}&| z$JeHUZ%XZUV?MOqA#Hh{#K}qJOyl#~vG~#QqQ4|9B~`8&jgmL zK#^GH#PJA!)&2Y|i~T@Uoh_-|_9RdHAP~cKH$i6rs+SBIkbbW%osnrI2v*S_qPJfx z9Io*kWPi%Cg`$hQTA~nCsZwV{&5nIEKRGM!;W!kv>hi_eZmS1cL85$~l-cA)ez|c%Lr9| z%TXekg%=jvFhBSMB(elTMRa#~;tYRB1QAPz{-%!YB7jTcnuW^M+|dT)9` za>~dcl3|_UnJ#3ufYE~?Vh0h0_$+T^$mE%xDAvN~z@FmPs0^pDJ=rSNUwgU{} z4DwMKja*}T^pR>5u~cmhSk2nj!(RE*`n-<>p+$a6Q#zrFlQMd0_Xk6X*kv5OVl~mx zhUnP>7(-|>UIW&!Q|G4pn0oe>nzT8%DlLXdo zvffUa&EUwhbnr?=!95uj(l!yv7*e7p>ksPH^KF59GuT+R(i(NG@f}}BMrd`Y;tFgt z+3QrB7&f*n`FL#EvZeo;az(y=oi~EQFF7)K@Dlmk*y0B@Y*BcR!e;P2;y_BdJxvFd zeN?b$3b(ZKX9?3!X+oQ+{3vGX0ifei_2(bLyZOVgzui**P;XZT_4y~b)=02x0Cs{E z#`nHz2lOLIbkxgfS7cXkqfs{MC(C^zvg>VSVH5WF7>otGSdUHi-Z5noLMbNEV&-wc z2rR&?9>wzzBQzwn$TCt?tz9o;eF>)T z@ynHgMRIL8j#x!@Q5F4RIpHenziv2* zPQ7B_T06&ZF=vI$q5c}$CzXD$Jw_XnOek2EnT_wYKQNAJ0~xW%@Umt8%?Z850EyW1 z=lK&DfSxOEzs{fHeS_OxsoK^%3&tmU3S`$H_$}QAa!odHJYdY#s)ATbMYq~{JblgY z+p{U63a+{yDrIx7#U9-pKKGb>iX$XzIum7eU-@gsdk=mrIWZz@ru_M~huhymJQYkgL z2?LjRR<6+>H5@-^tLNQqOIy7z{-1*ibxLxbSjczN5LUYA&&9zp-gX|>>RKYM&^$mU zjXgPyp6=%RyZ-c6l!bF-PLE-KHm|P_-{l+9Gce)B#e6JN84Zr8i>oV=n5VH|t$6O! z1XKtixx9uW{PFRm83zlX)WJWK>dL2;RnoLo;M4dr*h9}g&eGusg&{E1Wsf}e~1Hf_1qT}kMvyt4SpuE4I*)a zykGO^L=|9h6yNb2K5AMSQBe;Jtl6*E1&HK#4Jt~1Y0WF`=;%PZ9uySR@ZRdX{pGU_ z=zO`i5c?k@6F9eQQv()N!456u9QWzA#1V@rd}4boAURp0sq`VN>(uo=2=h{D9v}7h z(qQXXPgP3aPeJ$I^HyD6Z2hOvQ3eSkf8`6cTPm~HoPG>4A`sj<(Wb*D{+kmgxAkP& zauFOV{#)Ro2;QuK#r64QlCF!g%-4Uh0AP2qs$Gb)us(F?JGcr47bDt4HwDJTvVRh2 z*{Be<`KKY5_9#LpQ;f(QEGHJOYr!bT9`E#{8b5)Vs3YG#f8H20-0EntK9Yf|pVBy1 zaE9qDbG5F)A%`U_uz(O4_2Sx<{EoI9ky#w9r|uaFIz>PH(?nnPw^s@hZ}Bq+7*^F& zhoS4n5oOX(SboQtMwkAye~ol#s;fj6Wxj%wxt~-rFUeQh`jV_nNgj)tz&;I{JZPqP zVzC>PVs5`{8hg!Fe7|Zdy+nQE;p==Wy~fU(JJ}ERjC=X} zU)x;v1Turh35*Z1vDYtLpFh+bBj)p4InR;&Em-7jDV2-fcga{sJ*_;I*K3#y#0q>j zmfy4)A6!wP%rAp)E z^mg{ZmobpH5!~FrOW1&+qXCM4$yS$L}V2?j0ZBUgnyUJ#GT?(ceG6^6~SRmK|hZ^=quVeUjf+{^6UTMa$7y#s1De z>=s{F&JI2KeWl|RfQSQ3`NKG=N2~(lx$rmm-6D0oO*VK>0 zmX>Ls(o~`!25kCKn6OzyQF374y?5`IuV1f)D;9x3l8Se)I1yf9~H zLU$4qruWZK%8M})%Pr(W?fBj~(6Sf96kgf)P;P7DG-3udRL+ApPwMS4WmjlV^&k+;8w5$mWLEMP!|dxr1jU~c=Sp|{sL zT+y+Vyz{m9UP3pZdv|}$-sw6n_3qgYSBLJ`{r$Vnxj<89=R7~U-Rgzo_7~5e??*{R zx85n(@!|#RxhU#yadn-qo12>vtisl(;K&+cMF0hor&j?c$@f%+p`i4kt_Fbju_p5{ zmP25SBfP;Q66X&`<^rJGPai*u3LuyXJrIO|x3CBj)(i#)AF(f@Jk%jhTLqX8|9FDG zr)Ojn0WKn1hku-85x}!dco@9x)psW5ckBu#dfZ5 zFsW%o>oI1szoUTmY!*gbLqo_M>p%t!z%s{i3H1qC0T-1$4G><#T?&XZ?;K$8f1dVU zR%StFR~gsCTMuv8x`E4q%dkLFN?NK(y6H)iX`E4u@pK=r!EHf&<4i7bk0Bzf1`p)_ z8huZ*#?W|bCaU!WR)T2|3<+zPUjiiKD^e`wRVcnJ_PU`(9G%&m>doe??Mn~s zp*;9AZ4=+Wvx}I?fJCLQNY-#nLC?ekH{4=sXG&+Bm$WX_?72Vd;+pCBGBD4uE+paZl^IN zCo!fmp5TzqU`>$|O*rq8{aOC}x{p3aqpxiZB{&UkQ`z@NRI_~*{%C+#x9BlQKG&x) z2Vm)ft@;}+5F$zZRW)3y`ag`lc{tT=+b?b&mU$+b#Y)m5Wr$*# z7Lhqp$ylf)=_XNzWz4Wh1C=R>N=3?CqOvq18WB>V5+ahaKi}@>`Mvx29sAhF{_lN` z_pX-Zy3Xr7Kj&xY2CW)Uqs2_Ojc{QE_Ld3iQLqRd|MZEwokf|36<|>v6bBqSHW3jK zz$14K0auLATMhY6k?kI&N_B5_uFLp{mToQzY6XwzIh7YcEa+A2x=ZXN^!<7|E(z-w z-ZDAR`PfZw2z?MFz78HtZ2-vX<^rlG&{88Mw%+#v|0v@R&AiW?J!5!yG5SjxpYeo#mqs%&-r5&< zV(Gfg5Sz0Xt`XEFWf;CdKlSd1j@M>i9K(%XEKWNrz6vYxL1ZUD=No}B;*~lG6ba3& zb*8I-qbYcQ03$=yxP#X83zsEkFM1gP@K*7z%~(6~`_7Sh!zW{jTK0vVtl!fY*c61Oa zI~*Jw&FkG3j}m1I{&X%(@rtm*GK!()@-5jNJ%dq2J~#tVHsy)lk0YVy7mx@9X~?=palvncL) zB9lEYUi<(Nzihqy7OW^cwmwH~$3QR?`y7W5GIeItM#4r&dp$oZ+o)M|hoO|^<_e4w z9=WCBBK{_U`+1*z#r?vn^%H=S2~3DexsPc)p zfq^hi*oWo%!kS%9%|6#qc%Z~VS&l;Oyng*UK4fe64kX{Gve)fPaJV&wv&9y7bKg68 z@9x(!c_w19RTOak0k~kiBE;}d9QSFLyvOO&xk}5$xFF*byKQ5!-d&&yrf*CpxdfNi zqBX#C(()aIjE;bkFi3sRF_|<2e=|$fO2y%=7?t|hbJ(nA)5 zQb38AF5(5jr5tU6FebAB;3J^8S=^qvRiEG8xzosTS0taH!*lTNbxa@n@?`;hBeR@) ztsH|Gk2G>VgzhBKz9Qv0L8y3O(IpZ6cVimg;2cy32~jD2Qkw3CH8i~8CgSGik`c*) za?AI6S&r-nM|ApD3;e(#-RH0mdmy|U+rxysLGv7aU}iaPO&?O?&p$#|9U`J8 zpaUWE_CoTRnd3a87VLGG=Vz_-e%ly71BzF&x8CI4_7f{kZ4Q5J;xI71()PZzN`Gx4 zJ?!CUKTs2YYB>1`|Fh|z6yB6;^0#e_r9Im>EKIORj=|HXS$G-0YU4{#c@7snzV~Bh z=Dx`a&%>diJJIfSrU(fL;O(JUYWAE-cC?uukdu?^lyFe@_3iC?`&O0+`sNK}FCYAn zD&mnQ%REo&_}=`>b*JjHE#_ecgWGnBBg9V1pud*3fCrx`b!zysF*08nwnC3LPS=>L zS>~?|8rTq63c?K6;^w@TB*e5wMAUAkfM0`q(S5vSan&F0tUO8@mg!V`$BJX&tT&tQ z)X`KT^i6VmQp;SQ<1u{S$=Yf%ZbV988%t@V*9O#t?McrnO$NsTt=5=8%K_JGd(5k} zMvvSE8Mt&`gB>7#IK?R3zU<4B*uBJ3zdIG2i1LjtUOn%Z$7&^IW@fs`JFW>+B^Y>% z<*2{!k8XPq`EzPniLFuIK<3r^a69~oMhYY>LBcM5cwdRYT(CRSxLRori-v>Dw8yOMI0C_%=1Ni#p3yAW? zR;-9CX4;Ep8DTrPr4pSOQyc3FssxsLDPa?*?~AdATH>^PaC{BqwoQO)=U8&>_B^Q~ zcC9IE;h?gq(Sy!DY6NJXWz~eFQB|lZMb@2SnjH66U2qsLzufifw~~4Fx|=EVxziDR zTlv`8-y5g8skpFDYZNNtaVbvfzG$ydB)uWx+If4H1I2*a9JIZ*H#?J~Mbd_-%1D>s z@hl#B*m@LigET2dwG$T;&>2VK2G6qOtxSl5N46BLk;&D43)8f=-dv<^w)G*OgA z1CDd3#REl2`4W~F{eB)4)4T2!$H*jNMyuGdwD-O%Qzx=LYFp#E8|PwUC+CyKzG1C6 zIx4ed38|8OJ4d4w!4BBpiCXGSeh+@5_`};VSQf%goq%>v@p_B%(S8wUtl7aB*9 zl7S#i9Y}T9 zNx$FL_GoWP;qnnu4q8rz1V}aAqCpZp&1uB0A8SX02P(R2>5>nxn#|?g@cF>Mx!h;> zPF1N{>qBmWHy*XG)4A&+dUQ8YIEjg@iv5AwgLdoXf|DmMef!2}GkxBscG2$sNr~OF zWzMxu-c62-yp-Icb%|I{7GiXfPH2|h9_%(gJWQX}D@n(iW9VzyxV2!_*&u=a?fE^GIf06lB$3+pyq+z?^r_?ln85*!ayZi7`+evxG3g__C7fF)k%{^hxWt>gTN8sc7EeQzL%uz`+EA z>NGIsN&cDquXwwhr9O_8gZ~VUlgYjp(gz)r zc0)_#vfKQ*rl|tkJfG7Fpa{LU2$7GHf;|6WuP@%HD9Yzw*X~!zIfj1f*Uz7z;3BBP zp4=u;&PoI#etCTW9QfsNd*0nP*3}hXYhPdPCP*C!f8*t(-hl2xnz4hWr~Ry6e- z+HDD8h?GrRJ1CJzPL^i2o5ZrqUCI&FE8*l&QjoycH+)>hYJBOfj9c8N6!d?#wIBY( zW}I4oERE%xLE{ZP@q&8OJdJWno`uI9VU=2!?@V6x2xr6WR+;N%N!?@=7~D-hA8r@^ zFqMhYr1eu{Ju5~;pqIJZLFy8J=(p)fn&L4N>nz!0J{(-FDscI#n4F$=sgZon5xsmk zjzaE2zwvjbUa$X@1RIXAut)rU$gF~~jp<9ad2lUPD(*Uq3`fkDK`dbgjD47KU>Xh= zn{5VfK|>02A>msB`vjNxa;$gL`x~h8BLy7X+{YGgwfuzAkWv+=iOKi|E(|z^UgEo& zV_2_$?Nl1=ERe}7sOu&3Au>Il(>XJJo^s7eMwS-u&Kl* z7|8dE!xU+ypYSi}43l<)YR{fVyME(FD*>E;h)P8-c)m1rol~Pe_S|RT1H-d4^dxtl zU}vX7%XOh*FRv274TwCFXu$$Zlyl_yMIl359aTdC8i&ka`&xui-8?I7T8|%HPVP6b z5>mFsz;X>b?0z3{&`0nA_p5?McEP?(bYu@wez9&3Q zida~cXZz`ws|M5fgj)zRE`{VWMp?tIZ!g9?_{M8T=2oAvKQ=82rSA#T-@%Y@{!&Wd@wX|->y+WF;}Ca*Ofw~o za!b*St?pSFsYJLjGNDQ)i9jToZG|92GY(ETC92r5S>@59FRpB&rqnYwi%qYXz9dUE zU|4*=+?z^07QmUM6Z-90H*S(Ph8Kp-P+~Re4j;zmsMMt%ll!JWk8I=IR`aA+tzUNR z$Wo7y+p9X$p@95-uEL;P=R%q)3XSCsQr{`;cHM|dF&yu^bLZwllUURv>Oh&>HTee{ z*1uA_-Lae^8Hza` zTL6m2bD?viF6$Ok|e*RRBxfmzk1!lMU~odjmHU4BZj`k;^RQyY zFTJT#`JVnwL1C8;4P}Zs7CFWVPYE{LR9?Rhd6f?Z>eqsd=AuyCP?R;=ESRxPO-&aX zV0_v6Pm3oln3|5|y|Dqf3&m&$B_ zuTWbnlSe7ArMr9j_g?~S=t{A?$6l~t!KgWf$WB-n~--pJ(<8wy=liQ?sv38{P+<|b_Wg&XzRGn;$ z;pfjh9kik*D-Ay@DEJZOP=~h$IqT65KM?JflgaXl*v-QaQ@sUE69RF&Pa=gVz*szAv2VWlukd@(?o6j2i5(uC_X4VQxRn zIdV1&XBU~gH__{BZ6z4sP!nmB&W77DFYa30Q&dzGL4&oY&HwzP zQDKcx>u`~lE*|%&E-L@p*C562+$FG*UF8)35xDvRI;^>Q^T~1bOr|c}3T0$uc&YvD zp%tVf->>_fJ$G&r+)p*=i!{&(RgxI%HcW1}m?=J7Pg0^cuERE?_-fNT>_zj`SoJKX~qpmkrmcWa}a2f0spfZ2O zoJkYSmZPO@OykL54(6HpaR}DQwRqBHLUXPlnH>v=0cmX?bKDycD0*O8o-D^O0xVF< z^$QzkfF&>~Jb^FWMnOm@6X&S)I~L90bU5}f2#Y{K;rW>7#yg7Qr|Gi$f#al2fCFU= zDK`uO&`r@d&e4B?ogM-_4vAV5co_hYy{q!)a?vkVp#|N;NAW`H|eV?__Gx@ zBo7sEzmsH%vHCYCE=6a~!pnn9X1;tWwIt~=5#9)B8wOF(MY4v9s2&>_8iJHU;^2() zPBZy4*@4Hbu!s?!;%<Ug>qx#hUyF^fvuZ2XFmzeQk}76c?Xd#~R`OH=RrN`zre| zGGawA3LdksxNsl)ZSjXGqL=LP%LMbe!RsztZPEUL=kPu+fVzet>0){cnZXgoAic~; z-7aq$0LtFJdWmuHtS_Y?zvI`9XY0>keS-le?Hc~;7BI-xBozB}U)!O;1{n=vgf~Km zl6Uqj|F7pypI*fW=jlLQUUhq}7(GdxpGe5H$;-`q0ajgZe3VNPF9(Pm;`ek&$>+ouB7~iBTF-I8;Fwu8wtbxL-db(1nq`{q?WtWa(w|5jycBt`7ahgiHB)B ztU+t>uAMVFBwB8&g_fRl6@uGqkoZ|na!QU%%Tv#g~GL9OUh-l#}%p8*T#he3NwS7@tcb zA*(vm(6BBF8^-P`|BW1%x7LiKrMgm4k)X4lPQ>ta@zh|B>UNy*GiVny}b z471HAwlI?V_*X%C92{<10g$3+XY}ml^F^hk^pM~V7`o7fP^7FgZP{sgoEkFuW za|=A%a*q=%mf8XqcP)!qoZHG?D6+srnk&Bmc{Y9muW;0=UQPuj=o_) z#(DV;#)^6LB-t=s{&rRDhVIDQu!4QWihPIXH} zMTP4@D+#KQObj~D7TUXWC=l0@+z*6`Gyhq2_fA-M-UK? zGy%OmuR_Lq4R{1_Q3VAA?q9wL_=ivl2@1YQO}>IOl#`%oqVQVzaWG;Re*bn{HC&6$ zATHzyt?e*kXiUv66afsiT-=p9UbhxmNoAtsU8vuVU(l1@6)Vn!J}I~$O&=17C);k% z4e?dK#olMw4T^a5B^ffS34>h>eF;KuWEOV|JEK?_LxxkbA!NX$XwM#)^A;d&P)X}5 zX)5qvw~ls}4sW~w`%pjX14hDHN~~>c;D2c^k!D~vPWR?IAg=Nid-6!BGbbBQ;OC;g zY(6h-xhgCPogqZyJQjkmze>%_Y@^+N;VU!Cd8_iQRZQm}oZS}bjMP*oc653Qvm*J4 zr`sr6OLmWur4*>gt7Ibx;1TLtd%M>rIy1-pKx#EPKs=5`{S=>+9 zPFQ_=?G0lK|A#q*LF&|Akc03HV!Pe2)szcnuE%pC3NI--(?khSdrd5r+{2|MpcomO8U~I$uK9^oJLK7{z{kMg%Xg4n zhnr&r+^I`S-p}CF6^&AQeZo6cg;YI?1?v@$n>HSAh*x@8w09j-7~jc8;~joU6HK;2 zfd9ap#?Tfu|0&S+P3-k-!l@$+mBNGLUa++L;-3pKJA+GVO7oVcL6PJTq&2pRBw;$< zC1A|9>}9HdP*AEND6Ul~qD&914>6JyoSAZFbNWr&Z&uhajx=1`=?_M?2 zAcw4BHU^fHuGc)}3^Q`}(5uv!XsiMGuoeK=^6>Kw2R}>t36@Wrn%#}girpU$!bVXy zSoTZprnPoep6AD-U6!*jkFp9L0JHCNyE@xn3e51i=8og>@$7m_m(fc&G@oHy`2^~9 zsoaCBoQIxyQSRVcQeU6+0c#YsL3{OT*$qdc5JCH)MWFW>cv*W#`JZTMIzJ4VHf14sF<( zQPUV~Nm}F$-RbC=3X33w2P?iM z?oInowW=AI^T}3+;Qd$3dz^2)uFqM~G2))<8J>yjH|zy2ZNW26n>Stc0_o!aVyygzgM5#37*?J5LK^@(Q9IR~goG;DJy`DX@Q{J-R;haM%Nt35uwBl{^O-pgAQUkx;n@&Ligk#if4{y{+`5-u?S)D@eP zkENBE?fx$Q>e-m4ko2d}awZgGA-kTPHMntf@rbuHLx?EDMhhBVCqHw&0%ZV`$jpO; zpyzjv9%brb6YpRQ%7jq67oL0UK3|abL6EY0H=pBquuqVBHevc=D!bdqrHQ?s-A}Px z1jJkC5`Gt@H7qW?BUWR&=~xMAkjb>)sg3nvqslqf3fSRTL@SNJ)`jCjwzGlabEcU) z_(uawEDm>CqA{oK_)VJO*qh&_a}v#Rkt)+-W;rOu)#|4IwMrW0_tF;h3LQ>XY2nNM2jvU^t)vhiUBA zm@>p}fA#&BXvBf4)}UJoB7xX=Xll6AR;)_ICN4*WaB#qQJheAD+vHY<(H5>$-X&Ye zW^7p2GUhGd=1SK&&KYEZ!ujD4IXQWAkKq={3l?VWty?DUJV!Kn-T5TXiNzUYS@dqn zO&AnE;$$GCLrMJC0&YggQZ&bj;pZ*W zhmV|XC+Qe1brA5ta_RWi1D)LW5`cX)G&B(Q!6lr@B5O&)nkCOLhM*_lvf9hJg;Ez^ z&M_6Md2tv3BtC)_2|wL#JXs*xmDt7?Q%l^@nS%6#7=SrUV^P0nUREgwSTgnUK7A~< zhQuSz1Fg37LA-U9(~F?Ze(P(vSm)pF$f>V*+vKG*-0I#)wxdY8Zt69$Brm${i1zpK zVOwMK*+iz-CP%FOp&`}U@mrQBcK4}oH4emHPq?ziZIZDkQ-rQ(N;}yCKZ!ots9D_0 z?D|tqc_y*Wj(N_kmsXqa26C4I+a$Gjx5O5UaDGS3yBw70(t?SF+Dj{D-BW8|#&T)X zFZ=(^*=@Kv`{-wvb?z+~t`ijwydNIsFg3qXXDi|K#$2+rp?YkMF(^Bc2!VLwucjam z8zXXX(0#C72*&iG?>mzT3+31dBuBmijU7vEqCKB=qmKlT8c7Lv6>Z>1Tzw>P;@-1W z@CZKf)k1_NE;)9VXO?X-fK18U^~e3M6%6Q>I1twAdFQAA06G2wfWz!QOe(cZC@?ag zU{5_#cT~DC;qgzyi4#5Wk{3CG{$c1mQoU~s36DG81TnCkSCcH?EifWNzU1kP)TWYP zCb`~liIMY$iT|ZhpXaYcv@tf$XZ*77)(q9T`j#|}cxJ`_%XojK8uv|ZwY zO1tg`bri<-OE%Y9LHY&%FiL;%>x8Z|rAbLvct|MyaT!#b@B3D>OP5*iE*NExUvy|R zdwo=yUcxIKiaTfh?z_M${Z|FbUrn5}k#stKRnU3`<<7H$4R_F$+SWcL#Qj814j%@< zEdHldw6w;d`5Ikced9U-AACny?pr+)T7m> z(JDXQ6BQJxTmn}w+`R?TpqU+a=ZDJgSc$-oSdf=D>km*UE$7m-dZkoX50_gI#QwtQmTgsyX$ETHq@%lH(_!=gU(r(N?gHgk8BG#>2^b6BWo9kXWiehMm)lBA zZ^YOrf09%D0Q&Z;2^239i4-T)3p6y_nGBN}Zcf%N7NXa_eEatR_I10>mT5I#^~ zX0gSmdH;W!Lmv|pVqxuk?GGMV#jUM(FI)T<3n=sywgSQ6HfR)NO#m(Qk@z4rb@lV4 z+Do!Xr96`S2TWFzXyJz^2LK->`l7?d@eSR-KejNw7p-TO;G11=W3I{o1>=%?rScMi zl_}Kz+WqXx_aR+`C-{De^7iu|JJad|i|dFOi07sxbjIxq-?#k*Y4A{@mtai4|N524 z1HlFk^Wq)!eb`Eep$gsaZs>7`e6mK{ z!i8aAw*{i(t-p(d(-7Qe7+?r|X#@wY-faskQpU*Y`Gt?m*mC$>ilB;cupHohjg5<^ zLrzDe!zl(4%+USZ65|}bSBV8+m%W~yi-V24iN-1bz*5-M?Ax2Celg)@LQ49Dl-zPt z=jCFe@67M3S=?V{%$LHKxk>ylmSoQT@0ST4=n9WulbLIA4jK1P)SJQ94aFE9d)|BS z^R!+{QfIrIsAn4t;V!n>y!V5X82i7xssxF_?lgt%%=y)TWiso2`$z0uNbs-y@)a1S#hwweGG$NcxDHLlA(ii#NZyfyG+%(WJa{n$Fev z*L~#^eB5XX=FhTJl8o}?Zyo^uRMu9ECOxJhTl7VmWX)2nE4=XH&WIwlX-o;QXNFajhTgI-al^c?-4Q-zL{2YKhoH`ijdOr{7^r z%r#!!yy+hUt#`+gH!>TO28d3J9u@J|G~o9(WJ8Ct*zO-;Lu2Iu<)#rln$h~~^!NXO z(O>o#o&idU(gDN+i|qUdeOOP0F-loJ3I<+6zy<6n@K1RQfEhOn>v3v?zHlkZDvfeN zhbVhjx65({beCn7ZZKzMO8)ut$HA7^VSDNQc@GU759I2P2zu;UEOD~GYtnUYvL;~5 z;EfjR<`04BxrsqYCD%kdctt@={Rgy1pj%GymA8duySHG8K#wgoJrzj zuek>+z~USSkUn?aB)Zl9U;Bd+IWQXNB?Vv`5mxyG0a9A2CN<_0A*?f9l{i%(CRrI0pL0d zREXoy;_&sg2g9oxf0Ld3IE3PTQzKs8=1D)6W*52JDlmbKoV6;H5IuRvh{K$3xf6U*TsFDVc%^?h2vn0;U?jn~vRS73dQFX++m#X_ zzjK9!qrASNGudbSOGItOx?6gBX0X}F%MZ}*-stuMOX*JAZR8W2W8U@UCAqHP*E;Lj zKRL@h9s_dR%#Z7pl+{P(H8%MP2OF&P5qsBrM11B210Z2*10ny%Qx8;y5Y9b2x2^_C zv!W}-aq`@4n6-wTbcz79K2PCe#ll_nL8U*hhV=&x&r&`~O_RHd zp8|PL(fx$Fen+*c$Ss~x{)!G<`me=I5*&#sgw>1R1i#?)*$!6f2Kf_&Z{TFI`KqPH zd$u1>#9F#TLQ1!$+NJXsxkJ{8?Km&VVr+~nW_|HimZB@3BKzLU^#~O0F)#ki>uRwv zrUUi8o9dQA8yze^QR|>_dFzg*!0gPpb0-1=A{v?c#Xe$R_df1l!vBV~`W6oL!wa6c zDfBXRw{pU90xx5P72gM`hLAz3^d`nyxLc^czqELU=8du+QS@G_2Vt@0C(5?y8yX7A z=$Hrl#glm&u|5ch!cMPkaaFa%$np^h-GC03x@HA$HBkOG0@Gj&`Wr&5aO!QZ$yCgh z0BM)QpIw42_$gtgxO{%f#e#T;)Ywg(dVoszYw3~VyxR`0Y0s`c>#)~pK?twMl2 zVmt`8tN9{0GKB$Nn&w<4_X0^|YoKH$>TG7pgsUA#7Vt(QEC``P%teBDKU6>$q_13oi@g23xDv_dD6>Duh*2N zR0cS%vF9vUy48ODh6n?f$QK%euWEg+I_tHrm5;s@?(9^uGx*03M^c@%xiN)y9FS-) zA-v>5x0>xl7+e{dnJr$F#@R=S7kzkJI-+9ZO~*b}ci14V#A4&=D7?w^RYhkAAj6;a zDoW*jsU5(!+yx^rGB825d%~1KoHc-*t9SXZ7miK0cwLRUfsVb-|P8 z>%c%vO`Suv=)oF6Ye;M$hi9;56Z`*<%Ulb;yu7AR1>YLR&6@}Dq;#|7waH($;v6;n z+wt-%wQ>lCrBoX#kGx=}Pj-x2`=>Xl*-H!%?iM~i#YSHo$iBpk7?;S#>W`g#sFZQo zOL)&DR+eHpiRV||*9uQ5nD|7d9=e9C_b9PY2;Bfw=i|pa4w#gLBcOVG@YK8U2d!oI z*U1M&=HHgfxZ{(5Ynjp4ev5(T6;n8+=-FE?Pv9T`CXD}uF`8R z9A^spX{@&H;$K*T&e8eyYkYw5j~}_x-(&2Ab{3l@Q2&ba?gLfCVvUk50$~-o-rvNj zV-=$h#SI6p>=0ZWJx5kHXWgz4`)e-lqO(Uxkjahi{$^E`6UO7H;g6pjR&*>A9p!8_ z#iL;vJ_dEth*x`hTj6dZ{ZvhDC+N6LMC#tA=IVX^@?{%9MsNz>zI}@+Sb9Hl-&hv0 zy&?|3>UZxwdrA&FWN`ec)#y)$Cdqe##gGb_LSZnmhe3Zav7;_@85h3?B2vJE7+HcT zB2j(4Qi7L55qc|J{+#7s-qr{$;f|W0{gx@E-QSouYW4-yhlu&0Tu1JN(vyu&3U}2X z$P0^fuKC4F?R3UOo^+SjuYTu~C3m;{HKaYnt+R)VyWSKCo;%4^1r~(rw$a)udoqGsR6x}e87w`fO6PFAvVzH3MlJ~ZZ;CT#R%u!J8J?u zm1oBAH2;<9Cg1ft-K-?_&d|{Cq3>{qH%Umy%AO~(4X0||!7*JVwp9eD#{vW@+`4x6 z3(X#NsNdj5C%qro`|0|&2BQ%{=E~kIsZ^x{x*@Ur1b}eY`kw<;Jn6KK!vcS5Qz_KO z&qhdLGq2-uIW`wzob+<&`7(`zk_M_;8sACks^}@$85# zamS`M>sSuN)IvWQLkMIpQzJJ+euGEl&Wh>JFNJmhe%0)Hif2bL2g_&68B?KhZ2N&e zETFWaK_z-n9&#LP;nFy05zBKq=zhKvk6!Lp-L)Z6cZI{Xv`5tfv60vE1$Y$ti%o2M z&ulr`CzdPGI14;-=LJQ*b{*kqnF!mz38OlUwAbdX2+rQItyk#3%_{4_?dXM zXs-6IqW9NC@41)D_+E`Rd0dK-yQ-YVoJPxCV%;a4n)pcWuTnZY)~}gg5H5toqWrYB z*=!f?BcU|LFCG{NnA^=F3eWZbiv>(nj`(qo-UfgU_BK&Z2ro?aX;2YRXjC;duYg5@ zdSr$u5|)GP897d3bU)J}C~`xf$R$zNYfn5{H0Q`*B;VUOtNfd9OiF)S=;akH;VA0B`7O#iuqbF{xgvF|NdPg?}il0&(;f9hi2J@~`=@BFK3=NHrL9TbGDkn)_X zTwGiaM`5@3N|i-kD(AY3iO$TEv^G}$gZZS-dKsh*mH#-tCGPR4_YLJRx< zO+gT5XP&mR5XGCVvCjLzY`Vu9e?P1)Mh+HXUqK7MX>GqZ_&J%8x;;yL|+|NW1F zZAsf{m2c;O2pG)i_^|h1ypX(eVByW=8L8J9b96m5%lYuejEuvpeSJG(3ibuB|3jUj z%dVejb8V`$O*@`d3VceLUQ-hu$cZPu+pJg*QfBhxT6h`-GAFW6oq{l-ZrT$_jSs5n z^Hb}TRQvpzLF{A93VdmT$?oBZh~})E9QreyH}+?$%Brhk1It&v7l@q98UTfgE-olJupLwap9|%my$Y#7R21@KqWt3 zB%O!}uSPq-LI^p484xOR>aKJB3?2uJ*f^)%nOop!wSd+a8GfsrE?}xe#M_qJQFY_X z8oL#H`TXC00W$ap{gA_iz+(_kg9*yyn&x9*A0|aO4@HBLk!BC_jVVo19gD0V8>(in z7K>5z%l70I!vxd!aeg=-j@2yY?{8 za)Jb?#wCPUwp*s_${@ADMh?bBMbBCkTA+jy>eq2luI5VWD5|<~1KmTugCuQeKli!q z-`&}v$~XEwkTQ6oMp6+CUc^=Se=3v7JUf8lDhLa+SYcnnaKs~~sC_xMueW!Ci(gPs zGWBEJH64o5u$=eN1jZHfk~lcIugOomH!sDU)G%6a@S4`R`hjK3-51kCeG@f_<~tNp zxt4;suMhhje49wt1rYugyB4Nohb>S9IM}H+#IP2j*v6KVyCk2)Z|J_>uh`{+f!4iDp;+PN)zP*yhpi*9U7La+$wdiPF2iBoC# z+<)8@538$Mtby6eTGVvF z_FPy_8~mAjFBH(=prB|xkVR$}*V+~V_!7Qbuj&q{%V&2;?R@kVX%17n#5yJSEfaYed3Mk|Zh z9#Og`33B9z;o+Rf44hcl;7(_5_(N8IqI9mi^?f-M^Mo~2cz8H@Rh2585&oYn3MI(C z7tUR0Fgf;x%br^L@s_Y*8h@YP(|h_dgWKgEi|Faj|xf)_c#ep-R}0;&O<$?9^TI$Pb{!QsMo)(^G4!wzRS z=?Ic|8Mc;~EC>^E?&)6a-xjd#^f;VBErTvIgiry##M5iadT4sY5f`J!?pU|Ly6UwY z2@Y(m7WH;^b{~E$jR?g)eHYpV#et#9ofsfwklgzk|1aER z{d+sWKmvCc546_STVL=!CTB-lVtU|7NyeGx(X{udymf1R8B4C&ibfX`w5BB=?ttfl zZxOK};rPm6#$xJMZ)e%bPQbPvNnAzZt>)$TE^Tl4fi}IX=BE!Xm64GVA)J{q<;mQ1 zuV7A*m^g6*0evQw#cJC|!5#JPHd8K#b-(exCq}TY9=KR=WbE~gi{qUdBeO@ryuf)I z?QdFlJ1;j^X&m<)f1MwjhlYt=1e$*!f0N8OLTu!O)qJ32b%<|3ZdNfU8hKtyo= zl9K#FLMFg65z*7q5)?9%QM_<`8%pgW)N^%?ofx-?6v{Tt<>*hlQS@PIU8H%~@qBCa zk1t#JU$hJn))IM}z_3yt4~JegWo0T(r?a3DK`rcfb|nyZ%#!Ybc^7Q^sqnm z)-9dO60RHJdGF6t$b~5;hwi#x!E3xU7t8?EoQ|U{&+oRjvg>Hf zdxJF-zlbsOLx5;Lr?gHBJI{O>f-w4jM=0LL*t{WnUVOZ{xf%KhIekE}jy(Jai6ml% z5hE1k0|Eg#Il0!B7C-ZdBbdA*rr~MQZr-tqe&_6mB8iOzWWOc$APJnjiRtNkUZp#& zj^b&g$`~;Yj}rM3zS$#Hm$!b7MSosCj+yw^uV0@Kx&*r*H{x3QC<;4+5_e@;7FM$7 zY*j-FcO)F00iC!xUAq|FzUde8w%Q3m?L?|oE84gS(5r-3VemZZWLR0bcpy~1eg~Q< zynx2o>=Sd7yU7`b=L@ZHn z`VhWFs-K0+3TLxR&&Fz7Pp+kkLJ;5`W5AN7#`;cxME)=PLruA_4Qt!6xezp zrx`|=qdJj5)&l}Y=)7Vj)vWl%>mnGVA{{ z`#1a_1Lqifjx{tK9$nms2XF8lT4M}8$1-EDUE7C??o^)#rYyo|?{;-LMK#;5rei~K z6*5re_j4@%Pu-y`B_`>9S%pcfjre_E{tub;7I7C(5x&;gkMbo|=K_WmT5cM}?{!{z zHs>m;{@qP$wY5b8OK`{laEOjRobJ_K|HG253sdDiLUPoUDsJnjOezc%9 zz_rr-I?-F_<%1Ik!ZQqeM873v&Yeg0Nw(|1VNQNq;Xm-!ZV=ZEo0eF!18IG*W{|vD zn#Xdy=iR#v%gm5((FCK@4n@3veph3}y4%i<@ z1*vfw6vFfC>C>kkTZ{nX;FX4CfvSBvORlP8t2A;Zs+cd`OwXBRK?#{-t{2T~L*7+2 zQtZmvBq5br94l^fN-Lc@v?4G3UvK1iVzU<@u+5^cN4$ec_Qcim58FmlC6FUDMGSeb$F1|gu=$sQnP3&M4Tc_JKpBa^6Qm}eF2`EC02K&gW5;Wr#?rZ1 zu1p~NZ3Z-y1fOcqhE^FsMuq&IS=5&xt?Nx$ABmvS?}uCHyeLJ?&)8>s>{dX$x!}qH z{L7&H;fYToI{>_oG7FqjP>NTEjzFp%^=XDi-drkXrE^?Ca$+Z*bl zLh@~>cXHS1@>NUw<$!cl#E6t7eT|=o`;elKm)8KqP;1Uy0FDyCy5$cVc|||KIfbhV zNwsePJHnxlShtO;$d!a(&4AU#?tXKcEWQS+zmhe8>qFQcktNuW99^_fHiiC&7^80N zvZtekT-oxaziI0Yellh37~A;>ogLt2tjpeG3mU|VxAWo&&fw#y3;(4{{}ivoauK+rmuJh#L=%=r zVq*_*c?;G4Zi1C;{nv!xpn4BKx=eU7xUkH0p&p~=uV_^?tsRucP@x%Bly<@FOw4ce zfxpowfls@UtkH__de7TYysbCEh0bG3B8A3^tb?1_t1;l%@hAAUx_MF`N*5I1T}SPN z1rqB8g5fD_z7)~%O)4gc7ZPWnt!$OIoX=z9PK%-^ZO~9!(YsVh-x`%+sc zEOWh6&(nB>ws7dA?i^Ig(1hRw_r7#p4qHi#N1>~CpxK)k@@lZBz^^qOe_em@@)Ewa z3%GRa;r7J zbttyez(MaalVo39D{WR1@GX+AWC-Qy1}eXFW?D!B@eOXS!~g)6g;$u|IPR+S*O2DT z*AO$=KLik&ZHUt)=0ApCmyoGCqev5Dy9e5nSHHsgDEAdwX+a}AWJ@SXsg>?P%hG{I*hs^C~-bh!_WlQsSmHCI{brE^)V z_q9veNxjylr_kz{^2Nla*P>Ep<&SythU#&=`kA-oV%0wbSf!(nPm+gq!4sL)J0a9s zr>SY%WC(Olx)LOi|AhJ!#h0BTocVtbVZ{zu2N@W}*REaLS%t03=F7DG z3zTS3MP7i3d~m#1=E1GagEylJofXkyesDa8M>!bP11nW=uELt4O)HpFkG5}61yV|N zG_DR!$~n(L{a#;_E0 z-!Kvj2D@kSC#Mj8#2&JfSkY^hjov*Pf_xn;FO-DFp%k*g~9 z;Y+x~WXe`E_oG^ML=ujAgM&&JhjU=kSVHPv3JD>%!|sw7nBQ_T%(HCh{l5E)<_5H2 z&;0%$WEXGwtP#8!Tsv&WoZl^*M&pD{T07n{zYJ{0u&7qOz`!H;-0<=JW=*1L+xXv8 z<>5O3F;ARzFR%stR)NF`THgNH1EIIJ?*m+uY5=xCR-?|xi0khCg_C4<-$eQP#)K*c zM*-YqXaf20Nyt9@PpK1^oz}KmhYF81=Fm@Sx$x3N$1Y%P*t!4)$viRKVVQ@E$?N}{ zXU`nrv3v4PFNgSt?rpD>VPqkDB{+v;InX|j-G`0^OH6N$g0R5Bc=I*SbRBw9(j$)& zCn<5%5ng{YN8q3zELE9&d)Yp3U#ow5o)7RIaSm8oUDsIQasQ;r_9aFU z*H6lqoJkdpmupDnE=y0Orlslj9pM+~l=W`=)REY^AC*F&S@*JTJvG!P4e| zoprdR0w10^Cem;)QIzhh;akWS_&sHmIN1#{1-N(x7=+=)UmO|{u15J3J;qT zYm7LXN~#lVG_vXUOh#G19*=bL^z;Nmf9TZTYosgfFJ~19bPHr%#eZg^ zad84Q_owcl+WG%ZEJ&L9f0$oD>Vi+wy~F46o5Gn{tvZah15>tz2W9Qr@$T~HxWF*b zF@F;XXc_~!Q~evjD4_3RwE^f4MPoOO8P+R>g0K3V8XG^-2Kiy1&*8&|5h@4g;HVY> zg*l=*-oo*3giGTct8kor6!~2=Cj3)BF|*7{5`fDb0pN}S#rmCRHb6IU05^_a!s_G1 zi4)9HP#e)b#wF5i+oJ#e{42%vljSL!xh&ZGe6Z?ue!gfB#9a{5%Kc|l)>;Jzxsph% zyZLQ&w0sog+D-gZ@9%2e0dR9kOgo)luvpU-(_Opv z$M^3C!oy!q-+Ku(G2nq~JCZRU#-ss6ydY%b4ieqyKmYt=83fX5Eld~SIx!Zz4BNS+ zH*5x;E2P9tDoP&$r-tS#$Hx5TJUPWsmd)Q}WAS|6O?cv2ln*!<-+Z&Vl-+(<*%?7s96lKo+I#* z#9d7iQspX{zz(70Gxm6h+9?Wuzg>9A5)JX=hXDn^fWe_P>k$#5XMj*-#P1-} zme+!(LqnpHlZ+xDzY7lxtnQDuaZ>J*LQ!?geD7H=50tM?@t!p673=;g6gyD1`K4!!t(*P6ZlhGdQYiaGORNHqcuv>p6?Y^2I}SZIfRw~z#A z%TQT3@%enL^ZkB}=ku|i6^|kf zHA*WR=q-3oKZ2m+U6dE@7s@48dXD*6gAJ;Dhl~?yn0O>49)J6QVS?7d6Fs?jV9>r} zgh>^)3AqH<3tNXce+)Lvk%cKJjhgev#_smxLc&}&-0xk`W8Y56X15l3zKCLf=T&N2 z2BJEqp;rDznBXPNRiP(IQ2B+{3oHL71O*#HUcLljd<5VLj&Sc2XnEDpsK=- z!87YtrN~m@6U5InvfX(2lb}0>Xbj@JlW3C9$U0(_2H}dbX8?^7upJ2O()@hX$G^L? zPM%l0=MQ5ay-sC{^56-n$!ak?U>lAs&u9>PW1x!B_6knKVkQUMo(SmjTgaDvOsjY| zpsJW*5G83%Brq|_g3gi?wYv=k;7Py(CCY*!;o+$>QoIN6B1acBo|)>^(oupoy_>Rt z?I*RZm3mPMv=#b5p1v7obMt$e^eM4+cKrZur8cw<=tnPK%}P+eFOTY>4{tK)w1TOV zVVU7@T*u?boPkXB;tf)FdR|nVIrGL=|CbD}EPW}1DBke1H#aTJ9~Gt@JJyU@+oDWs zs!o*0I3H*ZzJF?M&k{r&scDBo{(}WH(4(j{CM#49wZuy7jOzgCnT};!g#u4~4PwF| z5^h;+Cdy;C{46f*iCG#mi(?Y{;)EUM@_pD5~!(geywLuLO=cpz$&`3YjEOd+kQSPT{#(MUzU&C@q2~9v2q@o^-uZVmI5E(e$b3n9y7U9wkea-dMR&<7+re^dDGcK6U$i}X z%Ra2V*pk3kCC&gp>BwJPT6$cd^kQc+^mro=_xk%MQAZbc3Vw^lG=)#Qn=a!fYz1QGQ4^)j1E2g?|au&ungoT0`Zw+ReNWqC& zu0a05=U8de7SIRvwp|`kr+1Jym7Z0L=TA&aEXvvx$8W3!z|H(I-MLffupq%u-mql5a8@uac z@kMa^=M{+vgHf;T(ek$se~yBeUvMo$3LqMV_VGQJCUgGuW7m$qy9(y4-J5W$4$MXf z2r-IZwK$0FJ+^t|^XKeNxMt*dGdY)P&|*hWDla@wDmP+~Us^upyD&mvOPrkdS}H_k zULiD3XY;Z-#=u0_*-_5+m28;cNQMY%d}R@wWkBU7h?^c>i8#33-Mw@v?iy25VOOj% zk4#y=ZeC)Qh?624d#~J+?Hx6Q?{J++fG7@qe$+2|;t?KKAkn@uf_K`MmCD&%y5SWl zMi@pLy*kiRuS1e7fl3`&UA}f!AkKEUm!8mu#y=LJznpL(ef%L2CJvoKn;s`C>rV(V4(-jg8X+2hICzzGGLi)NGphJx zD+U}gnezY!N_Y6DP|iX z-;kH=-`lUOPBn3cYmJ$A8dK2FFEah`&jhYxIQ4zCSza+4)k!X&+xt-3@Sbz6e6^U6-Y&QFIpKL1G=U+pzc5-A(AxCMTuSX;r=4Es09R0?TAI z7?Lv@&J8b9NZaN}>znYt66~!Kzo*cqFWmXsoVb8nJqiy9u-W}^#r!lPJAOSZ7Y-{0{77PNJ|~a`~>- z)fu(8?X5^bHGkIkLV_o?Ctaws>5ODhSXljuQ`xSYJlRioa9Xgt?VZfy22NoiH5~tp zcQf)msCOKErEhQOp?S$eq_p(S&97-e%~A1lBrdL!$@F%E{ZDuc!@g#2>M*5nCcrEw zx@xTir_%KHOYvJ9q>ffScr~b2{(LI1l#RfU3gVw=ZER#afBO%I5XYrFa41A4xHn+E zEC{}F%&~f9AC$c20wlHo{G|E_rz&9cl*c_pr3JI!3v``qpZ4kM=%7^;whG5JVQPkL zehP&GF|Q7bKdHbT6I%qcpd7&1%4ozk(D$1CH5;mXr?V6#!X^hx$ux*zB<$Bb+KV3? z`@}e5zw%(VlTl@-1WV{%O=gG0w{B>oa5nX9*=)g3x^$@lPUR9;|A+{cyuW2&4olI* z?Vom2?j!wc+3Yv?dko*x9Shu2n`FPg;am=Pv-OCkscpE)jsof%&mA@-HQzjHjxUSz zJcxaITCePg*K*z3S8+HXFK@d>b9f&2>8$f>VR*g}j6+~mcrJttLTeT>>=D{O=s_>; zy~fI?7={535I7mezrK6q)>*!%W#*iM6Ba^JqZ9>18?K_QC(*#?TU|Mg^JHq)oLo3J zV=#}pEmvSQxAN_iooupW8e}pl@Ytq)_YKeT6-%E&q~W%PHwMxok{a-ww1)np{&6T! z#+A%+wfykJ(T+H#C0mo+!tN}|i_DvjN=*T5v-)x{>xAKse!E$7N5TTdP^7shPnot9 z;kq_azBWWMEmIb+9jn$(SRo^+ZZ03t*avP8`Z`HxjKZ7&&An{i&gywCIC+C?)W*|a z$Mf<0H`8w!W&G;ba|FhUl7VFYlLHTJ951G^bS6NR_!cup01l@)z}XJ8T8bP^ za!rX>P1KyM?8%rZ=srBv6q3ZIlnwWMaL&hv*v=fwzl~!!l`FR*2SL+hMpuqr+@pQ zoVm3!M+pTTy1WY*ux4Uc^59A96|cMHTEgBD7U>==tbfNM1`4jOajv$bKL7Q|o%gmR zCeb~w?KU4WB!;s$?8N3GBqVt9O}kMFF?LXYzj^Ii2=ol_o(aHJ!3$_v#?f9?cq*M5qi%0%Nn(?VvZXC#S7x z&;@OD@>Bw*Gg&a^bjb)=FffTO%ONXUGhct(b$6aMC2NEQ9rkX&@{Pq^=)#4?ukXC% z?=+m(4l#lf;WD6yjfZUI6L<&NiKj}M_esmlL?BoEZEABA1f#TX#Lw^G^%sov^@Dl^ za>Pli6VSQ!I*Z`EyHj^vf**3^ z8=<#%>wSsf;kok>Qbbduhk#V+e61`y%VHPUU@#-@nw{}!g;t5v944g57#={>I(?28 zofNboc#;?B`~0rOi%**=Qo_HLn-4yOhWIq~x{V%iczSO!q6wti6C0naM4?LGxYw+F5JAprq&lC8ggIg|??y zP%vEGz54Ns45DTBNB{WoqwmVq(F)@t`$Zh@0)ry}20~K@K!7vvq}7#^lgmBqa52pa zPiB<)P$f1dz*NUyh~|F`od$~g5{;aJ6p1Cyij5ndD*f6nvfU%M1;-=f%YoE7~ z-UH9R z9T`$E%n|RLZUIWf6IUZ1_oR;kGfX}$=^Bmf77;f>Fo*^@RI3v$TXNmCNpw<}r%E>} ziHsa5sH89c#c^(`?_B2somEq%GHRh`~#PYarvKDhpiYAHEnK@u0ZFNLg*a9&k z)2p1ef|=e-ic3vX6QN*i^H6K)Vn9sJJgd=LIig#o=00GxyD}ibTyR4qC~-U%hOtYC zG0baLU`vtQEe*%`9B>T8{=kWNe4SfeXM4LZlqE=#gY7BZBl~Gf>>rrITi<_uTEWT| z6F@@$isYYlcuvAXLMwx=URtnNB}PJ4o+2%ox-hWk5gO6cWFMM(P77x27H8X4(=aC4 zDH${rLONRkTVPpmEn&uX;{F5B6Vn*Pk!LsUxJ>LDVZyj=@d{%m`i>2m8;hl{PFI~T zr_IQ++sY0NfVpLo`a8NJk~y*_m@3wi$-&61KW$uy3wsB0r2JXw5T(Qn-_e_7gDdg9 zR5yGf6foMjiJm>#CArW6`H-krF{Ez+un;k|$&Mq?&<|s^aS{Gtl4OcJFF3vVLR$3L z2p3z4YdEb;$))CwgZhiZ8{Td}T9w44-QYZ5rle)+T$`4nORVFwkr@{oHb zqf+Z>_CBXHKRfby2AS>j-&I6`9@sw9i<+*zu@;&J)4}=^y&XZo6TmMPJ-;*oZq>*w zVy`3ovm%!->Xr#T@$u4Aa{zc_IR$6KKql zVkEVH2+-eCGvFoAL@aR3A7}f37)Ac1Xsds?@l#71n+HcW&m)8HS6uR+X(rKsxx%Ie zkb#s0fN5|0hD*0!x4bnM$0lq~kju%*%KkzrJN5=jau|IbtQ;r4VCP@BcZnN$z{J!&A}1d1d($uAN%+ZPFHZ}w}}YdI3g_&zV*E0#|hR;?*~+>@ZprRiStHy zq}djs$AsjdXU9hP4fPeeQc3g8{|MnG9*}-$e1N5~van=iWT4QPk40W^!3=}Az}Rs) z1qJ2|6iK&`4~u!uIgVhZ{>`VOgwvbdM{k7@93uw1#m+;aA$W?HNT73cbW~DOf|m)( z!06DTgtZag1OQ8d2K}WJAoKD6QQlC2C;|xDsjZ?cgmk88sC93rK~K<&I}Y=|g`zQ-E@oN+nt^BPZ)|JKw;%Svt#LvbzBUF?S>KXOu690;n zrvqZ7=Li6c4Iv>R0AJwz$DYBrWETrSQ<*8AEcv77yuSYH4=ATk7oprZih|U{Bq=j9 z^ZNDcGZKgv5f+}o*b5S=IMD32g5-&F=XOAkvRxxDU*5hQ!BQwCdH3Aw?Y)3+COjKd zN~a+VN)9chhu6NSuuy(8N_)iFi(=5%>uECu*fN0RU>Ldy0}{AB|HbV>slZy{3_@eD zW{M0f(oUo4%$e;dsmgUXZd}2wrVx2?z&>eAz0P+Qx#5wT#u1gWB?=T+fw0i*H( z^Q^rv`eB{L^NDd*(dFE1K{X@!7VAxk5UVUhkUsZF`5zev(?wGEW0db%jgt~=`E0zCE}k1XWfG* zDv2nQDhq1q^APmY25_}}Nij%mY)mzC$p$z$TuW@%C4M<9Y(+c@^&s2Yqu?~{??8(5 zuJNF`5=&S-GEOFO_Gc@oC!nan_-^A}fiJI0z5WBakyrE_y}v-@;M1qv?0WF=)id-l zuyPd>I6TORj*h3*uLR~dzCzQ+{pb5~$*sUa7JcQppb0zDbXQ*=i_ZDn zT&~~yi-%c^-kt)JG5YG){G|2Yo#jiOdNy-T-N4Darb7>1lYA%ZH0@6p4XRIr7;zK$ zqqY9a^UG)8jIoKz+6h4>$M>{daZr&&6HFM;sysc={k(m2q!qqhMvy4@WZze@pxihc z?u}s3b_2@%>@31F*5?bbvSt!m&NYPM)lPL^=(2%x{K`QjPth@PaQp^-kEQ4x*Kp^~ z8eDm-(pnF9xPt5QzE-1QMbZ9oVqQZ=#zc_e^iJ^Cz|Z5aee2-Vk2rFqj0(a6D8QYd z;9W4gfW{O&&nGSC5n?+9O6`tq&6Wy`jJtMLH2!;%@BG5FW~qxHjx0n761_Fj#UuXB=T!iiCJ4H&z3`w zpr#*-+IO@O93{Y&u@J%oF3sO=drIBZHH0^V1up6ciyX4D)T14sWQuS*ocvRRm_{Od zJDPz_5H;agXESia$~;?d8bISAK)&Yi$P#rzN08wsSuwibq%UZ6`6>q5o<^09AO z7`{IlHvMCG%biRKCX(aU?&D#iBM%eXp+hhwMVar5(Y%t9X-1nW zFvH-_QBKC&nW7hJBhZ-3TR4G;KD+ ze)@DqE9xZ9VY*y*bWa{sb@11}^lEUN5fyr6RjodBb#Xv9EyXAi5CEfJ7Ohy8=&wSbLB8sqkng5p8AwZ z@#DB6+7G=VH2dg)6XCRNQ1cMxU=49$Cw{m@yTlbw9 z&E!*JC>aG1G0*)eI4gbYS#2)b^T_CTf7820Cgs2+StaW`Jm$Yq67};I?=%p=Fp$L1 zcprDVxE(tXgM2x<40%4~BTD-s1iy{*7IQ!#YQjMD4bd2Dp>Xb9s<5S7IgoJl zx~!1joW5OZ2|+9uRap-ct(tU&_uIE`?KS}2)j*_f55M$I@7)(17jxB>m0up6S9*OF zCJ>_LY!bk>bh z{4v`ITKh``;$j*scPM#|D3w5_P>w%mvQ)CWQNmKzBJI_h{->>(6(zuYdScPl>DUpalq-#2 zQ$|r3>VY)FF@=)2YwA71yrGzf%4nb(rambuDw?GJ!mNfITFdy!UvQ249++a01A6G|TQM=Cp|Aka)0H>uT<(nU zFtFP2l~l9Y-62!hZlQv4-}iD$)P1(L3Utp15P?V-$5A(FT}n*Xo47Hm>(#i3DW()< z6S^Hrmhxu`i&>y*H?luXK5^C|!NPpMaY>r+O!LL7UH!r&ZA3_~;vPoKu|%3~Kn;;< zBWuVr9p%{=YFf@JSg>i1{ARY6hH;=DSM+5h9E4T|ej~^d>57~jTfoc!MtpnL*2Ck{ zb>LR)pWhV4iku&7o~_>KRi04SSWV0Z-S}rFR9LWx7i((Jir;58R$4-6o;`jyNt5eP z^YMJsS=*PG@D)%)a&uH1#c={WCWBE{+#ys=P->c?#cY*nPPOxjebDke_00llqE_F< zP`RdilQ*?*z>Zo;l8nkH%sT|AOup`OC6K+vI3#XU312f{BSN|LmPoqF3ZL05OLx-} zk`nJ1-un(=EuhwDT#z7pQ`uwz(du~KI#TPRy!du{$M&RAA9)&*2l?h}m~C=t0;QkQ zCyml)Bn9)wT@m-nCL@f^TCDcTvaJ9?@kZujm~kBYZ~8t2IB^IQAh ztYwPaF!Ab|0a4V!De@kr(bOu^yk{{d)BU7(voFH4Dkx5HC4w18HQ2fdIu~O(ue|~e z%uYEd=f)JvNqe?hBktYjNXOefh-4;Hu?4j$CwNkoiFL1M+rviNk+ELp3+gf-esF7S zIy7e6a}%DA-f(ZNeX^h05|0X4(=Eg`1tnH2pIdripWG4u9oLs)% zRF?U6e6Fh6pfIjD&g%o9Z4=>BVDV506^D$paOf|AJ|4YwrZ1!)9+{+WsTU=ecieFS z+HHfObsB(af#Wb*0=41DNr3_bH)b?oQKOXu`7;jykA#1IU2vPSg3zi_eg2$B;jcPU z{=Nayyk60U{fYn41!zMob17)J;v-^W3Ai?>nwFd;6}$>(S*TPm&Or#)UBMq=*Y4@g zdrp^>g-&kIeiiDUqU$Y)JXV*}y)37%)wkNIGQ{~565dXTTCSc)TtCZwuf5}uor6xI z{tmcm9>K>4377Y5Su45SG%CI!&NebH@sg=xYK!lXt9XEPo3>haB3SZ%UJNBPIM{0# zz{@R7gjnvy9>kR-vy4BggNKGilSwcf!to&(l?VmYSq(M2WMMwmx$$3j0 zlcH;M1zO$2=TENN&5!YEUU$4TJ4nwy2x=X1CL^PzD_6GaZ3_C6bN4z`=EcZ2%Z54? zbcS90*I4iHjNhQ81xNDlf7|Wbf}CV{bIn@boLk!b?sxdfoozICV+CG#UO!m*$nE{c zZ$lcpk6r(EAkyu0S=snfOKTzVRwo1!bFZrU$#ERwPI{?g`ty$a!1bP5_I#SjTdm!h z+mcG>HlFt4lwn4*->3#2W|kVb^c-F-lmG@zgvr$G6SjJCWtrL?eBzhC?3RS*{xDbB zuC$3}=PF84JMoEK5s8tEsGCxbKJa9ztnAgwX!KVW4hxU5QKi)*&aj^VSw%z;X{Iwp zU|C?LsEYAM4|`u{O%T-~Kb4jV%X>4DLy(~U!qUX7KcZ1)TDi~lvr|qpQ*8!H+RoUcy{KHRMfn+;NP|}`n}KB&#%DsVdg^* zS)&-0cS^x=Kvs~oP`!`lEMO+67rwr{W_*&Hjg1XF7=~tA%{fPY95%tcljB-@U8d#Y z%z#5#>kH>2;6V9p%HF`hALpw6adr6PR+CrbZdGIQ+;CstMYP1ksEd|ZeP0+T?2#qG zB!OcfYXiJHpAi5G!|~^-DZ=EB0}sihfAHHKe0#CKN{o`7-X8sBERWIb8C#}k{oKi# znxfjl#i9iLh%(%t_iPNBHmPVt4%iTPtY0f;%g@g1-e z5WAG?VsMHbsqtp77UhF(nh9$x{F=TL

O*3?HkX5>_Zr7{Q?g@Kn;M&*k0fr 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�hsZN4fsM3E3&rp&^J{ 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

ErQf6?8Q7SVIp0CvdgV?O0~m$3DkA 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�o$sdOsljkmjcCzVHmyg96<#nyGx8+$ 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 QMLb32QyL1{au;s?4>J4&xc~qF diff --git a/test/hub-e2e/__screenshots__/darwin/hub-sidebar-populated.png b/test/hub-e2e/__screenshots__/darwin/hub-sidebar-populated.png index 281a7ca0a8c949abf588cfe2d83a023a033473e9..6c9ba23f8af678b3a157c1786220a1267e703602 100644 GIT binary patch literal 21110 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 diff --git a/test/hub-e2e/context-graph.spec.ts b/test/hub-e2e/context-graph.spec.ts new file mode 100644 index 00000000..160a170b --- /dev/null +++ b/test/hub-e2e/context-graph.spec.ts @@ -0,0 +1,46 @@ +import AxeBuilder from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; + +test("Context graph preserves knowledge positions while revealing direct code", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (error) => errors.push(error.message)); + await page.setViewportSize({ width: 1440, height: 900 }); + await page.goto("/knowledge?fixture=populated"); + const graph = page.getByLabel("Context graph", { exact: true }); + const knowledge = graph.getByRole("button", { name: "Project Hub read boundaries · architecture", exact: true }); + const other = graph.getByRole("button", { name: "One snapshot per graph request · decision", exact: true }); + await expect(knowledge).toBeVisible(); + const positions = await graph.locator('button[title]:not([aria-label*="code"])').evaluateAll((buttons) => buttons.map((button) => ({ label: button.getAttribute("aria-label"), style: button.getAttribute("style") }))); + await knowledge.click(); + const symbol = graph.getByRole("button", { name: "createHubServer · code · fresh", exact: true }); + await expect(symbol).toBeVisible(); + await symbol.click(); + const details = page.getByRole("complementary", { name: "Context details" }); + await expect(details.getByRole("link", { name: "Open in Code" })).toHaveAttribute("href", "/code/symbols/sym.createHubServer"); + await expect(knowledge).toHaveAttribute("aria-pressed", "true"); + expect(await graph.locator('button[title]:not([aria-label*="code"])').evaluateAll((buttons) => buttons.map((button) => ({ label: button.getAttribute("aria-label"), style: button.getAttribute("style") })))).toEqual(positions); + await other.click(); + await expect(symbol).toHaveCount(0); + await expect(details.getByText("No explicit code grounding recorded.")).toBeVisible(); + await page.keyboard.press("Escape"); + await expect(details.getByRole("heading", { name: "Follow a connection" })).toBeVisible(); + expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]); + await page.getByRole("button", { name: "List", exact: true }).click(); + await expect(page.getByRole("button", { name: "Load more Knowledge" })).toBeVisible(); + await page.getByRole("button", { name: "Graph", exact: true }).click(); + await expect(knowledge).toBeVisible(); + expect(errors).toEqual([]); +}); + +for (const width of [1024, 1440]) test(`Context graph remains usable at ${width}px`, async ({ page }) => { + await page.setViewportSize({ width, height: 900 }); + await page.goto("/knowledge?fixture=populated"); + const graph = page.getByLabel("Context graph", { exact: true }); + await expect(graph.getByRole("button", { name: "Project Hub read boundaries · architecture", exact: true })).toBeVisible(); + await page.getByLabel("Find in graph", { exact: true }).fill("snapshot"); + await expect(page.getByRole("status").filter({ hasText: "1 matching" })).toBeVisible(); + await graph.getByRole("button", { name: "Zoom in", exact: true }).click(); + await graph.getByRole("button", { name: "Fit graph", exact: true }).click(); + expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(width); + expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]); +}); diff --git a/test/hub-e2e/hub.spec.ts b/test/hub-e2e/hub.spec.ts index 82161d63..fd3be6d3 100644 --- a/test/hub-e2e/hub.spec.ts +++ b/test/hub-e2e/hub.spec.ts @@ -68,11 +68,14 @@ test.describe("populated development fixture", () => { await expect(page.getByRole("heading", { name: "Overview", exact: true })).toBeVisible(); const focus = page.getByRole("region", { name: "Attention", exact: true }); - await expect(focus.getByRole("heading", { name: "Review 3 proposed Spec changes" })).toBeVisible(); - await expect(focus.getByRole("button", { name: "Open Inbox" })).toHaveAttribute( + await expect(page.getByRole("button", { name: "Explore Context" })).toHaveAttribute("href", "/knowledge"); + await expect(focus.getByRole("button", { name: "View Relays" })).toHaveAttribute("href", "/relays"); + await expect(focus.getByRole("heading", { name: "Take the handoff waiting for you" })).toBeVisible(); + await expect(focus.getByRole("button", { name: "Open handoff" })).toHaveAttribute( "href", - "/inbox?view=review&proposal=proposal_01000000000000000000001720", + `/relays?view=mine&state=open&relay=${readyRelayId}`, ); + await expect(focus.getByRole("button", { name: "Open Inbox" })).toHaveCount(0); await expect(focus.getByText("Take the handoff waiting for you", { exact: true })).toBeVisible(); await expect(focus.getByText("Continue the handoff you took", { exact: true })).toBeVisible(); await expect(focus.getByText("Review local context health", { exact: true })).toBeVisible(); @@ -98,10 +101,8 @@ test.describe("populated development fixture", () => { test("keeps Overview focus priorities and exact destinations honest", async ({ page }) => { await page.goto("/?fixture=populated&overviewFixture=pending-review"); await expect(page.locator('[data-overview-workbench="ready"]')).toBeVisible(); - await expect(page.getByRole("region", { name: "Attention", exact: true }).getByRole("button", { name: "Open Inbox" })).toHaveAttribute( - "href", - "/inbox?view=review&proposal=proposal_01000000000000000000001720", - ); + await expect(page.getByRole("region", { name: "Attention", exact: true }).getByRole("button", { name: "Open Inbox" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Explore Context" })).toHaveAttribute("href", "/knowledge"); await page.goto("/?fixture=populated&overviewFixture=relay-ready"); await expect(page.locator('[data-overview-workbench="ready"]')).toBeVisible(); @@ -141,7 +142,7 @@ test.describe("populated development fixture", () => { await expect(page.getByRole("heading", { name: "Overview" })).toBeVisible(); const caughtUp = page.getByRole("region", { name: "Attention", exact: true }); await expect(caughtUp.getByText("You’re caught up", { exact: true })).toBeVisible(); - await expect(caughtUp.getByRole("button", { name: "Browse project memory" })).toHaveAttribute("href", "/search"); + await expect(caughtUp.getByRole("button", { name: "Browse shared knowledge" })).toHaveAttribute("href", "/knowledge"); await expect(page.getByRole("region", { name: "Active operation" })).toHaveCount(0); await page.goto("/?fixture=populated&overviewFixture=indexes-missing"); @@ -279,10 +280,10 @@ test.describe("populated development fixture", () => { test("browses, filters, paginates, and restores URL-backed Knowledge state", async ({ page }) => { const errors = watchBrowserErrors(page); await page.setViewportSize({ width: 1440, height: 900 }); - await page.goto("/knowledge?fixture=populated"); + await page.goto("/knowledge?fixture=populated&view=list"); - await expect(page.getByRole("heading", { name: "Knowledge", exact: true })).toBeVisible(); - await expect(page.getByText("Browse durable project memory", { exact: false })).toBeVisible(); + await expect(page.getByRole("heading", { name: "Context", exact: true })).toBeVisible(); + await expect(page.getByRole("button", { name: "List", exact: true })).toHaveAttribute("aria-pressed", "true"); const summary = page.getByText("All Knowledge records", { exact: true }).locator(".."); await expect(summary).toBeFocused(); await expect(page.getByText("2 loaded", { exact: true })).toBeVisible(); @@ -301,6 +302,7 @@ test.describe("populated development fixture", () => { await page.getByRole("button", { name: "Clear search and filters" }).click(); await expect(page).not.toHaveURL(/kind=/); + await expect(page).toHaveURL(/view=list/); await expect(page.getByText("All Knowledge records", { exact: true }).locator("..")).toBeFocused(); const searchbox = page.getByRole("searchbox", { name: "Search titles, summaries, and bodies" }); await expect(searchbox).toHaveValue(""); @@ -1857,21 +1859,17 @@ test.describe("populated development fixture", () => { const utilities = page.getByRole("navigation", { name: "Project utilities" }); const projectMemory = primary.getByRole("region", { name: "Project Memory" }); const teamwork = primary.getByRole("region", { name: "Teamwork" }); - const comingSoon = primary.getByRole("region", { name: "Coming Soon" }); const system = utilities.getByRole("region", { name: /^System/ }); const projectMemoryDisclosure = projectMemory.getByRole("button", { name: "Project Memory" }); const teamworkDisclosure = teamwork.getByRole("button", { name: "Teamwork" }); - const comingSoonDisclosure = comingSoon.getByRole("button", { name: "Coming Soon" }); const systemDisclosure = system.getByRole("button", { name: /^System/ }); await expect(sidebar.getByRole("link", { name: "Search project", exact: true })) .toHaveAttribute("aria-keyshortcuts", "/"); await expect(projectMemoryDisclosure).toHaveAttribute("aria-expanded", "true"); await expect(teamworkDisclosure).toHaveAttribute("aria-expanded", "true"); - await expect(comingSoonDisclosure).toHaveAttribute("aria-expanded", "false"); await expect(systemDisclosure).toHaveAttribute("aria-expanded", "false"); - await comingSoonDisclosure.click(); await systemDisclosure.click(); const primaryItems = await primary.getByRole("link").evaluateAll((links) => links.map((link) => ({ href: link.getAttribute("href"), @@ -1881,15 +1879,10 @@ test.describe("populated development fixture", () => { }))); expect(primaryItems).toEqual([ { href: "/", label: "Overview" }, - { href: "/knowledge", label: "Knowledge" }, - { href: "/specs", label: "Specs" }, + { href: "/knowledge", label: "Context" }, { href: "/code", label: "Code" }, - { href: "/workstreams", label: "Workstreams" }, - { href: "/inbox", label: "Inbox" }, { href: "/relays", label: "Relays" }, { href: "/activity", label: "Activity" }, - { href: "/playbooks", label: "Playbooks" }, - { href: "/catch-up", label: "Catch Up" }, ]); const utilityItems = await utilities.getByRole("link").evaluateAll((links) => links.map((link) => ({ href: link.getAttribute("href"), @@ -1902,20 +1895,16 @@ test.describe("populated development fixture", () => { { href: "/health", label: "Health" }, { href: "/jobs", label: "Jobs" }, ]); - await expect(comingSoon.getByRole("link", { name: "Playbooks Soon" })).toBeVisible(); - await expect(comingSoon.getByRole("link", { name: "Catch Up Soon" })).toBeVisible(); await projectMemoryDisclosure.click(); await expect(projectMemoryDisclosure).toHaveAttribute("aria-expanded", "false"); await expect(teamworkDisclosure).toHaveAttribute("aria-expanded", "true"); - await expect(comingSoonDisclosure).toHaveAttribute("aria-expanded", "true"); await expect(systemDisclosure).toHaveAttribute("aria-expanded", "true"); await page.reload(); await expect(page.locator('[data-overview-workbench="ready"]')).toBeVisible(); await expect(projectMemoryDisclosure).toHaveAttribute("aria-expanded", "true"); await expect(teamworkDisclosure).toHaveAttribute("aria-expanded", "true"); - await expect(comingSoonDisclosure).toHaveAttribute("aria-expanded", "false"); await expect(systemDisclosure).toHaveAttribute("aria-expanded", "false"); }); @@ -1924,7 +1913,7 @@ test.describe("populated development fixture", () => { const projectMemory = page.getByRole("region", { name: "Project Memory" }); const projectMemoryDisclosure = projectMemory.getByRole("button", { name: "Project Memory" }); await expect(projectMemoryDisclosure).toHaveAttribute("aria-expanded", "true"); - await expect(projectMemory.getByRole("link", { name: "Knowledge", exact: true })) + await expect(projectMemory.getByRole("link", { name: "Context", exact: true })) .toHaveAttribute("aria-current", "page"); await projectMemoryDisclosure.click(); await expect(projectMemoryDisclosure).toHaveAttribute("aria-expanded", "false"); @@ -1940,9 +1929,6 @@ test.describe("populated development fixture", () => { await expect(system.getByRole("link", { name: "Jobs", exact: true })).toHaveAttribute("aria-current", "page"); await page.goto("/catch-up?fixture=populated"); - const comingSoon = page.getByRole("region", { name: "Coming Soon" }); - await expect(comingSoon.getByRole("button", { name: "Coming Soon" })).toHaveAttribute("aria-expanded", "true"); - await expect(comingSoon.getByRole("link", { name: "Catch Up Soon" })).toHaveAttribute("aria-current", "page"); await expect(page.getByText( "A personalized summary of project changes and team activity is planned but is not available in this release.", { exact: true }, @@ -2021,7 +2007,7 @@ test.describe("populated development fixture", () => { await page.goto("/?fixture=populated"); await expect(page.locator('[data-overview-workbench="ready"]')).toBeVisible(); const sidebar = page.locator('aside[aria-label="Project Hub navigation"]'); - await expect(sidebar.getByLabel("3 proposals awaiting team review.")).toHaveText("3"); + await expect(sidebar.getByLabel("3 proposals awaiting team review.")).toHaveCount(0); await expect(sidebar.getByLabel("2 open Relays for you.")).toHaveText("2"); await expect(sidebar.getByLabel("1 active system operations.")).toHaveText("1"); await expect(sidebar.getByRole("link", { name: "Team", exact: true })).toHaveAttribute("href", "/members"); @@ -2044,10 +2030,8 @@ test.describe("populated development fixture", () => { const disclosures = { projectMemory: page.getByRole("button", { name: "Project Memory" }), teamwork: page.getByRole("button", { name: "Teamwork" }), - comingSoon: page.getByRole("button", { name: "Coming Soon" }), system: page.getByRole("button", { name: /^System/ }), }; - await disclosures.comingSoon.click(); await disclosures.system.click(); for (const disclosure of Object.values(disclosures)) { await expect(disclosure).toHaveAttribute("aria-expanded", "true"); @@ -2061,13 +2045,12 @@ test.describe("populated development fixture", () => { await expectAccessible(page); }); - test("captures the populated sidebar with counts and roadmap destinations", async ({ page }) => { + test("captures the populated sidebar with Context and Relay counts", async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.goto("/?fixture=populated"); - await page.getByRole("button", { name: "Coming Soon" }).click(); await page.getByRole("button", { name: /^System/ }).click(); const sidebar = page.locator('aside[aria-label="Project Hub navigation"]'); - await expect(sidebar.getByRole("link", { name: "Catch Up Soon" })).toBeVisible(); + await expect(sidebar.getByRole("link", { name: "Context", exact: true })).toBeVisible(); await expect(sidebar.getByLabel("1 active system operations.")).toBeVisible(); if (hasReviewedHubVisualBaselines) { await expect(sidebar).toHaveScreenshot("hub-sidebar-populated.png"); @@ -2082,33 +2065,24 @@ test.describe("populated development fixture", () => { await expect(page.locator("#main-content")).toBeFocused(); const routes = [ - [/^Knowledge$/, "Knowledge"], - [/^Specs$/, "Specs"], + [/^Context$/, "Context"], [/^Code$/, "Code"], - [/^Workstreams$/, "Workstreams"], - [/^Inbox(?: |$)/, "Inbox"], [/^Relays(?: |$)/, "Relays"], [/^Activity$/, "Activity"], ] as const; for (const [link, heading] of routes) { await page.getByRole("link", { name: link }).click(); await expect(page.getByRole("heading", { name: heading, exact: true })).toBeVisible(); - if (heading === "Knowledge") { - await expect(page.getByText("All Knowledge records", { exact: true }).locator("..")).toBeFocused(); - } else { - await expect(page.locator("#main-content")).toBeFocused(); - } + await expect(page.locator("#main-content")).toBeFocused(); } - await page.getByRole("button", { name: "Coming Soon" }).click(); - for (const [link, heading, copy] of [ - ["Playbooks Soon", "Playbooks", "Reusable team workflows are planned but are not available in this release."], - ["Catch Up Soon", "Catch Up", "A personalized summary of project changes and team activity is planned but is not available in this release."], + for (const [route, heading, copy] of [ + ["/playbooks", "Playbooks", "Reusable team workflows are planned but are not available in this release."], + ["/catch-up", "Catch Up", "A personalized summary of project changes and team activity is planned but is not available in this release."], ] as const) { - await page.getByRole("link", { name: link }).click(); + await page.goto(`${route}?fixture=populated`); await expect(page.getByRole("heading", { name: heading, exact: true })).toBeVisible(); await expect(page.getByText(copy, { exact: true })).toBeVisible(); - await expect(page.locator("#main-content")).toBeFocused(); } await page.getByRole("link", { name: "Team", exact: true }).click(); @@ -2175,9 +2149,8 @@ test.describe("populated development fixture", () => { expect(footerBeforeScroll!.y + footerBeforeScroll!.height).toBeLessThanOrEqual(viewport.height + 1); await expect(sidebarLocator.getByText("Runs locally", { exact: true })).toBeVisible(); - await page.getByRole("button", { name: "Coming Soon" }).click(); await navViewport.evaluate((element) => { element.scrollTop = element.scrollHeight; }); - await expect(page.getByRole("link", { name: "Catch Up Soon" })).toBeVisible(); + await expect(page.getByRole("link", { name: "Activity", exact: true })).toBeVisible(); await expect(sidebarLocator.getByText("Runs locally", { exact: true })).toBeVisible(); const footerAfterScroll = await footer.boundingBox(); expect(footerAfterScroll?.y).toBe(footerBeforeScroll?.y); @@ -2228,8 +2201,8 @@ test.describe("populated development fixture", () => { await expect(page.getByRole("heading", { name: "Activity", exact: true })).toBeVisible(); await page.goto("/members?fixture=populated"); await expect(page.getByRole("heading", { name: "Members", exact: true })).toBeVisible(); - await page.goto("/knowledge?fixture=populated"); - await expect(page.getByRole("heading", { name: "Knowledge", exact: true })).toBeVisible(); + await page.goto("/knowledge?fixture=populated&view=list"); + await expect(page.getByRole("heading", { name: "Context", exact: true })).toBeVisible(); await page.getByRole("link", { name: /Project Hub read boundaries/ }).click(); await expect(page.getByRole("heading", { level: 1, name: "Project Hub read boundaries" })).toBeVisible(); await page.goto("/code?fixture=populated&q=hub"); @@ -2309,22 +2282,22 @@ test.describe("built production Hub", () => { const response = await page.goto(bootstrapUrl); await expect(page.locator('[data-overview-workbench="ready"]')).toBeVisible(); await expect.poll(() => page.url()).not.toContain("#token="); - await expect(page.getByRole("link", { name: "Knowledge", exact: true })).toBeVisible(); + await expect(page.getByRole("link", { name: "Context", exact: true })).toBeVisible(); await expect(page.getByRole("link", { name: "Code", exact: true })).toBeVisible(); await expect(page.getByText("Three knowledge pages lost grounding")).toHaveCount(0); await page.goto(`${new URL(bootstrapUrl).origin}/?fixture=populated`); await expect(page.getByText("Three knowledge pages lost grounding")).toHaveCount(0); - await expect(page.getByRole("link", { name: "Knowledge", exact: true })).toBeVisible(); + await expect(page.getByRole("link", { name: "Context", exact: true })).toBeVisible(); const [knowledgeUnavailable] = await Promise.all([ - page.waitForResponse((candidate) => new URL(candidate.url()).pathname === "/api/v1/wiki/entities"), + page.waitForResponse((candidate) => new URL(candidate.url()).pathname === "/api/v1/wiki/graph"), page.goto(`${new URL(bootstrapUrl).origin}/knowledge?fixture=populated`), ]); expect(knowledgeUnavailable.status()).toBe(503); - await expect(page.getByRole("heading", { name: "Knowledge", exact: true })).toBeVisible(); + await expect(page.getByRole("heading", { name: "Context", exact: true })).toBeVisible(); await expect(page.getByText("Project Hub read boundaries", { exact: true })).toHaveCount(0); - await expect(page.getByRole("heading", { name: "Knowledge migration is required" })).toBeVisible(); + await expect(page.getByRole("heading", { name: "Context unavailable", exact: true })).toBeVisible(); await page.goto(`${new URL(bootstrapUrl).origin}/code?fixture=populated`); await expect(page.getByRole("heading", { name: "Code" })).toBeVisible(); diff --git a/test/hub-wiki-integration.test.ts b/test/hub-wiki-integration.test.ts index 572425cb..8e9c106d 100644 --- a/test/hub-wiki-integration.test.ts +++ b/test/hub-wiki-integration.test.ts @@ -22,6 +22,8 @@ import { WikiEntityDetailResponseSchema, WikiEntityListResponseSchema, WikiRelationsResponseSchema, + WikiGraphResponseSchema, + WikiGroundedCodeResponseSchema, type HubJobKind, } from "@mex/hub-contracts"; import { afterEach, describe, expect, it } from "vitest"; @@ -104,6 +106,9 @@ describe("real Project Hub Wiki integration", () => { headers: { host: HOST }, }); expect(unauthenticated.status).toBe(401); + for (const path of ["/api/v1/wiki/graph", `/api/v1/wiki/entities/${DECISION_ID}/code`]) { + expect((await harness.app.request(`${ORIGIN}${path}`, { headers: { host: HOST } })).status).toBe(401); + } const spoofedHost = await harness.app.request(`${ORIGIN}/api/v1/wiki/entities`, { headers: { host: "localhost:48482", cookie: harness.cookie }, @@ -159,6 +164,28 @@ describe("real Project Hub Wiki integration", () => { expect(detail.provenance?.id).toBeNull(); expect(detail).toMatchObject({ relationCount: 1, backlinkCount: 1 }); + const graph = await parseBounded(await harness.get("/api/v1/wiki/graph"), WikiGraphResponseSchema); + expect(graph.indexedRevision).toBe(detail.indexedRevision); + expect(graph.nodes.map((node) => node.id)).toEqual(expect.arrayContaining([ + TOPIC_ID, DECISION_ID, PATTERN_ID, LARGE_FACT_ID, SPEC_ID, REQUIREMENT_ID, CONSTRAINT_ID, ACCEPTANCE_CRITERION_ID, + ])); + expect(graph.nodes.some((node) => node.id === TEAM_WORKSTREAM_ID)).toBe(false); + expect(graph.coverage).toMatchObject({ nodesTruncated: false, relationsTruncated: false }); + expect(graph.relations).toEqual(expect.arrayContaining([ + expect.objectContaining({ type: "implements", source: expect.objectContaining({ id: DECISION_ID }), target: expect.objectContaining({ id: PATTERN_ID }) }), + ])); + const code = await parseBounded( + await harness.get(`/api/v1/wiki/entities/${DECISION_ID}/code`), WikiGroundedCodeResponseSchema, + ); + expect(code.indexedRevision).toBe(graph.indexedRevision); + expect(code.graphRevision).not.toBeNull(); + expect(code.groundings).toMatchObject([{ + requestedNode: harness.symbolId, resolvedNode: harness.symbolId, health: "fresh", + symbol: { id: harness.symbolId, path: "src/packed.ts" }, + }]); + expect(JSON.stringify(code)).not.toContain("fingerprint"); + expect(JSON.stringify(code)).not.toContain("bodyHash"); + const relations = await parseBounded( await harness.get(`/api/v1/wiki/entities/${DECISION_ID}/relations?direction=both&limit=2`), WikiRelationsResponseSchema, @@ -267,6 +294,9 @@ describe("real Project Hub Wiki integration", () => { expect(await mismatchedCursor.json()).toMatchObject({ code: "INVALID_REQUEST" }); const invalidPaths = [ + "/api/v1/wiki/graph?cursor=next", + `/api/v1/wiki/entities/${DECISION_ID}/code?limit=1`, + "/api/v1/wiki/entities/not-an-id/code", "/api/v1/wiki/entities?kind=decision&kind=pattern", "/api/v1/wiki/entities?unknown=true", "/api/v1/wiki/entities?limit=0", From 7f4575f540959372d3eace12eb17519fad91a023 Mon Sep 17 00:00:00 2001 From: theDakshJaitly Date: Tue, 8 Sep 2026 04:55:25 +0530 Subject: [PATCH 03/19] feat(inbox): support contributions to project knowledge --- .agents/skills/mex-inbox/.mex-managed.json | 6 +- .agents/skills/mex-inbox/SKILL.md | 18 +- .agents/skills/mex-inbox/agents/openai.yaml | 4 +- .../mex-inbox/references/cli-workflows.md | 18 +- .claude/skills/mex-inbox/.mex-managed.json | 6 +- .claude/skills/mex-inbox/SKILL.md | 18 +- .claude/skills/mex-inbox/agents/openai.yaml | 4 +- .../mex-inbox/references/cli-workflows.md | 18 +- .mex/ROUTER.md | 11 + .mex/patterns/local-first-team-state.md | 16 +- AGENTS.md | 2 +- CLAUDE.md | 2 +- README.md | 10 +- docs/design/0.8.1-release-plan.md | 99 +++++- docs/design/inbox-spec-authoring-contract.md | 39 +++ .../hub-contracts/src/inbox-knowledge.test.ts | 47 +++ packages/hub-contracts/src/index.ts | 38 ++- packages/hub-web/src/api/types.ts | 2 + packages/hub-web/src/app/App.test.tsx | 25 +- packages/hub-web/src/app/HubSidebar.test.tsx | 7 +- packages/hub-web/src/app/HubSidebar.tsx | 7 + .../hub-web/src/app/inbox-knowledge.test.tsx | 119 +++++++ packages/hub-web/src/app/inbox-page.test.tsx | 34 +- packages/hub-web/src/app/navigation.ts | 18 +- packages/hub-web/src/dev/fixture-api.ts | 30 +- packages/hub-web/src/lib/inbox-change.ts | 20 ++ .../src/pages/InboxMutationDialogs.tsx | 322 +++++++++++------- packages/hub-web/src/pages/InboxWorkbench.tsx | 60 ++-- skills/mex-inbox/SKILL.md | 18 +- skills/mex-inbox/agents/openai.yaml | 4 +- skills/mex-inbox/references/cli-workflows.md | 18 +- .../__tests__/instructions.test.ts | 4 +- src/agent-skills/instructions.ts | 2 +- src/capabilities.ts | 54 ++- src/cli.ts | 8 + src/hub/__tests__/services.test.ts | 37 ++ src/hub/services.ts | 34 +- src/team/cli/envelope.ts | 1 + src/team/contracts/workflow.ts | 50 ++- .../__tests__/knowledge-authoring.test.ts | 62 ++++ src/team/inbox/cli/__tests__/contract.test.ts | 32 ++ src/team/inbox/cli/__tests__/target.test.ts | 84 +++++ src/team/inbox/cli/builder.ts | 16 +- src/team/inbox/cli/commands.ts | 46 +++ src/team/inbox/spec-authoring.ts | 219 +++++++++--- .../workflow/repository-team-workflow-port.ts | 32 +- .../__tests__/application-adapter.test.ts | 79 +++++ src/wiki/application-adapter.ts | 12 + .../__tests__/authoring-evidence.test.ts | 67 ++++ src/wiki/model/authoring-evidence.ts | 121 +++++++ src/wiki/model/operation.ts | 18 +- .../operations/__tests__/operations.test.ts | 93 +++++ src/wiki/operations/operations.ts | 19 +- test/agent-skills-content.test.ts | 8 +- .../team-inbox-spec-authoring.contract.ts | 190 +++++------ test/fixtures/capabilities/ready.json | 7 + .../__screenshots__/darwin/hub-activity.png | Bin 189800 -> 187084 bytes .../__screenshots__/darwin/hub-code.png | Bin 113067 -> 110178 bytes .../__screenshots__/darwin/hub-health.png | Bin 138315 -> 137185 bytes .../__screenshots__/darwin/hub-home.png | Bin 235427 -> 236011 bytes .../__screenshots__/darwin/hub-inbox.png | Bin 154632 -> 152774 bytes .../__screenshots__/darwin/hub-jobs.png | Bin 107911 -> 106680 bytes .../__screenshots__/darwin/hub-knowledge.png | Bin 130412 -> 127550 bytes .../__screenshots__/darwin/hub-members.png | Bin 128432 -> 125661 bytes .../__screenshots__/darwin/hub-relays.png | Bin 136237 -> 133072 bytes .../__screenshots__/darwin/hub-search.png | Bin 130408 -> 128178 bytes .../darwin/hub-sidebar-populated.png | Bin 21110 -> 21714 bytes test/hub-e2e/hub.spec.ts | 49 ++- ...inbox-spec-authoring-real.contract.test.ts | 197 +++++++++++ 69 files changed, 2118 insertions(+), 463 deletions(-) create mode 100644 packages/hub-contracts/src/inbox-knowledge.test.ts create mode 100644 packages/hub-web/src/app/inbox-knowledge.test.tsx create mode 100644 packages/hub-web/src/lib/inbox-change.ts create mode 100644 src/team/inbox/__tests__/knowledge-authoring.test.ts create mode 100644 src/team/inbox/cli/__tests__/target.test.ts create mode 100644 src/wiki/model/__tests__/authoring-evidence.test.ts create mode 100644 src/wiki/model/authoring-evidence.ts diff --git a/.agents/skills/mex-inbox/.mex-managed.json b/.agents/skills/mex-inbox/.mex-managed.json index 3ed7807c..c6fa5b24 100644 --- a/.agents/skills/mex-inbox/.mex-managed.json +++ b/.agents/skills/mex-inbox/.mex-managed.json @@ -4,8 +4,8 @@ "skill": "mex-inbox", "packageVersion": "0.8.0", "files": { - "SKILL.md": "ec0e61b45c9f2e2d70074bd613c0d294dd4d88ec73964e6187f0ac8d51de1505", - "agents/openai.yaml": "4dbdf205a76ba17d9fd8984c8d546b1d6628f0e135bbaf0c16c773f8fa6fc765", - "references/cli-workflows.md": "5147aa68c8fea7a96dd5c569c23570238e2a32a46655fd14267e31a7c5d12c30" + "SKILL.md": "e88eead3e97fe137785c4914bc1aec305969df72c10828f5dfeedeae22399ecf", + "agents/openai.yaml": "12a2827fe257c303d926122e4bb590910abd660e6451550a1db68a48037b4402", + "references/cli-workflows.md": "6c91905cc69d8ea47080630ee1551bf1a61ec33605fff01463d4a2ad71f497c6" } } diff --git a/.agents/skills/mex-inbox/SKILL.md b/.agents/skills/mex-inbox/SKILL.md index 4f6e5409..6bfe71f6 100644 --- a/.agents/skills/mex-inbox/SKILL.md +++ b/.agents/skills/mex-inbox/SKILL.md @@ -1,24 +1,24 @@ --- name: mex-inbox -description: Prepare and manage governed MEX Inbox proposals for durable Spec-family knowledge. Use when the user clearly asks to capture, create, save, or draft a MEX product Spec, requirement, constraint, acceptance criterion, or durable product-spec decision for team review, or explicitly invokes /mex-inbox or $mex-inbox. Do not use for email inboxes, generic notes, vague brainstorming, OpenAPI or test specs mentioned only by the word "spec," architecture pages, conventions, patterns, Workstreams, Relays, arbitrary Wiki pages, or generic memory. +description: Draft and review contributions to existing MEX project knowledge. Use when the user asks to capture a discussion or decision in project knowledge, propose an addition or correction for team review, or explicitly invokes /mex-inbox or $mex-inbox. Also supports existing Spec proposals. Do not activate for brainstorming alone, routine GROW upkeep, email inboxes, session logs, or handoffs. --- # MEX Inbox -Prepare governed Spec-memory proposals. Treat Inbox as a proposal workflow, not email and not a general Wiki mutation system. +Turn an explicit request to retain project knowledge into a focused contribution for review. Inbox proposals are review artifacts; accepted knowledge belongs in the existing Wiki Markdown. Ordinary GROW upkeep can continue directly. ## Keep the scope honest -- Create exactly one `spec.create` or `spec.update` change per draft. -- Support only `spec`, `requirement`, `constraint`, and `acceptance_criterion` entities. -- Reject unsupported durable knowledge honestly. Do not silently translate architecture, conventions, patterns, Workstreams, Relays, or arbitrary Wiki pages into Specs. -- Require a clear durable claim. Do not capture unresolved brainstorming as team memory. +- Create one `knowledge.create` or `knowledge.update` change per draft, for an existing kind: `architecture`, `component`, `convention`, `decision`, `pattern`, or `guide`. +- Existing Spec workflows also support `spec.create` and `spec.update` for `spec`, `requirement`, `constraint`, and `acceptance_criterion`. Choose these only for actual Spec-family intent. +- Capture durable conclusions, their rationale, and useful evidence. Do not dump the conversation or present unresolved ideas as agreed facts. +- Do not route session logs, Relays, or routine GROW edits through Inbox merely because they contain context. ## Prepare a draft -1. Distill the durable knowledge, rationale, and useful evidence from the conversation. -2. Decide whether it creates a new Spec-family entity or updates an existing exact entity. -3. For an update, resolve the canonical target and current revisions before drafting. Never guess an ID or revision. +1. Distill what future agents or teammates need to know from the user's request and discussion. +2. Search existing knowledge first. Prefer correcting or extending the relevant record or section when it already covers the subject; create a new entry when the claim has no suitable home. +3. Read the exact target and current revisions before drafting a correction. Preserve unrelated knowledge when replacing its body. Never guess an ID or revision. 4. Preserve useful files, code, commits, entities, and external links as evidence only when actually available. Never invent provenance, authors, dates, events, or history. 5. Build one request against the action-scoped runtime contract. 6. Run the exact preview flow and summarize the human effect before technical details. diff --git a/.agents/skills/mex-inbox/agents/openai.yaml b/.agents/skills/mex-inbox/agents/openai.yaml index 9e0ac8cf..de507237 100644 --- a/.agents/skills/mex-inbox/agents/openai.yaml +++ b/.agents/skills/mex-inbox/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "MEX Inbox" - short_description: "Draft governed MEX Spec proposals" - default_prompt: "Use $mex-inbox to draft this durable requirement for MEX team review." + short_description: "Propose additions to project knowledge" + default_prompt: "Use $mex-inbox to capture what we decided as a contribution to this project's knowledge." diff --git a/.agents/skills/mex-inbox/references/cli-workflows.md b/.agents/skills/mex-inbox/references/cli-workflows.md index 76e79582..c0f9215d 100644 --- a/.agents/skills/mex-inbox/references/cli-workflows.md +++ b/.agents/skills/mex-inbox/references/cli-workflows.md @@ -23,7 +23,17 @@ Use one of these command IDs: Treat this bounded action result as the exact runtime source for the request shape, available examples, constraints, preview command, and apply command. Do not dump `mex capabilities --json` or the full Inbox contract during ordinary execution. Write request and preview JSON only to ordinary regular files inside the checkout or an approved temporary directory; do not use symlinks. -## Resolve a Spec update +## Find existing knowledge and resolve a correction + +1. Use `mex wiki query --limit 10 --json` or `mex wiki list --type --limit 25 --json` to find related records before creating another. +2. Read the best candidate with `mex inbox target --json`. This bounded read returns `target`, `version`, `sourcePath`, and the existing body from the current Wiki index, without initializing or repairing it. +3. For `knowledge.update`, copy `target` and use `version.contentHash` as the target revision and `version.semanticRevision` as the semantic revision. Select a section entity when only that section should change. The patch body replaces the target's body; preserve its relevant existing content. A target can fit the read response but exceed the 16 KiB update-body limit; choose a smaller section or a title/summary-only patch when appropriate, never truncate existing knowledge to fit. +4. If no suitable record exists, use `knowledge.create` with the appropriate existing kind. MEX chooses a path in `context/` or `patterns/`; do not invent an Inbox knowledge category or supply an arbitrary destination path. +5. If several targets remain plausible after reading them, ask which one the user intends. If a read reports a stale or unavailable index, address its explicit maintenance requirement before relying on it; never fabricate revisions or silently refresh an index as part of a read. + +For create-time topics, find them with Wiki reads, then resolve each with `mex inbox target --json` for current revisions. Topics can be dependencies but are not Inbox correction targets. Omit topics when none are needed; normal knowledge creates have no relation editor. + +## Resolve a legacy Spec update 1. Use `mex spec list --json` to identify candidates. 2. Use `mex spec show --json` for the exact candidate. @@ -36,7 +46,7 @@ Do not invent target IDs, relation endpoints, topic IDs, or revisions. For a cre ## Save a checkout-local draft 1. Resolve `inbox.draft.save`. -2. Create a unique operation ID and a request containing one `spec.create` or `spec.update` draft. +2. Create a unique operation ID and a request containing one `knowledge.create` or `knowledge.update` draft (or a Spec change for actual Spec-family intent). 3. For a new draft, provide no unrelated expectations. For an existing draft update, read it with `mex inbox draft show --json` and use its exact current local revision. 4. Preview with `mex inbox draft save --json` and capture the complete successful JSON wrapper unchanged. Require `ok: true`, `mode: "preview"`, and `data.preview.valid: true`. 5. Summarize the proposed local effect. If the user asked to create/save/draft, apply with `mex inbox draft save --apply --json` without another confirmation. @@ -60,7 +70,7 @@ The apply writes only checkout-local draft state. It does not create a canonical 5. Apply the exact preview with `mex inbox publish --apply --json`. 6. Return `/inbox?view=review&proposal=`. -Publishing removes the exact local draft after creating the pending proposal. It does not approve the proposal or write the requested Spec change. +Publishing removes the exact local draft after creating the pending proposal. It does not approve the proposal or change accepted knowledge. The proposal is Markdown in the working tree; teammates receive it through Git. ## Review canonical proposals @@ -73,4 +83,4 @@ Use `mex inbox proposal list --json` and `mex inbox proposal show 5. Wait for fresh explicit confirmation. 6. Apply the exact preview with the same command plus `--apply --json`. -Approval writes the proposed Spec-family entity change, proposal decision, Wiki ledger, and Activity records to the working tree. Reject and withdraw make a terminal proposal decision without changing the Spec. Mark stale changes a pending proposal to stale only when MEX proves dependency drift. Repair replaces stale intent, clears prior review, and returns the proposal to pending without changing the Spec. These canonical transitions write Activity records; none commits, pushes, pulls, stages, or notifies teammates. +Approval writes the proposed knowledge change, proposal decision, Wiki ledger, and Activity records to the working tree. The proposal remains review history. Reject and withdraw make a terminal proposal decision without changing knowledge. Mark stale changes a pending proposal to stale only when MEX proves dependency drift. Repair replaces stale intent, clears prior review, and returns the proposal to pending without changing knowledge. These canonical transitions write Activity records; none commits, pushes, pulls, stages, or notifies teammates. diff --git a/.claude/skills/mex-inbox/.mex-managed.json b/.claude/skills/mex-inbox/.mex-managed.json index 3ed7807c..c6fa5b24 100644 --- a/.claude/skills/mex-inbox/.mex-managed.json +++ b/.claude/skills/mex-inbox/.mex-managed.json @@ -4,8 +4,8 @@ "skill": "mex-inbox", "packageVersion": "0.8.0", "files": { - "SKILL.md": "ec0e61b45c9f2e2d70074bd613c0d294dd4d88ec73964e6187f0ac8d51de1505", - "agents/openai.yaml": "4dbdf205a76ba17d9fd8984c8d546b1d6628f0e135bbaf0c16c773f8fa6fc765", - "references/cli-workflows.md": "5147aa68c8fea7a96dd5c569c23570238e2a32a46655fd14267e31a7c5d12c30" + "SKILL.md": "e88eead3e97fe137785c4914bc1aec305969df72c10828f5dfeedeae22399ecf", + "agents/openai.yaml": "12a2827fe257c303d926122e4bb590910abd660e6451550a1db68a48037b4402", + "references/cli-workflows.md": "6c91905cc69d8ea47080630ee1551bf1a61ec33605fff01463d4a2ad71f497c6" } } diff --git a/.claude/skills/mex-inbox/SKILL.md b/.claude/skills/mex-inbox/SKILL.md index 4f6e5409..6bfe71f6 100644 --- a/.claude/skills/mex-inbox/SKILL.md +++ b/.claude/skills/mex-inbox/SKILL.md @@ -1,24 +1,24 @@ --- name: mex-inbox -description: Prepare and manage governed MEX Inbox proposals for durable Spec-family knowledge. Use when the user clearly asks to capture, create, save, or draft a MEX product Spec, requirement, constraint, acceptance criterion, or durable product-spec decision for team review, or explicitly invokes /mex-inbox or $mex-inbox. Do not use for email inboxes, generic notes, vague brainstorming, OpenAPI or test specs mentioned only by the word "spec," architecture pages, conventions, patterns, Workstreams, Relays, arbitrary Wiki pages, or generic memory. +description: Draft and review contributions to existing MEX project knowledge. Use when the user asks to capture a discussion or decision in project knowledge, propose an addition or correction for team review, or explicitly invokes /mex-inbox or $mex-inbox. Also supports existing Spec proposals. Do not activate for brainstorming alone, routine GROW upkeep, email inboxes, session logs, or handoffs. --- # MEX Inbox -Prepare governed Spec-memory proposals. Treat Inbox as a proposal workflow, not email and not a general Wiki mutation system. +Turn an explicit request to retain project knowledge into a focused contribution for review. Inbox proposals are review artifacts; accepted knowledge belongs in the existing Wiki Markdown. Ordinary GROW upkeep can continue directly. ## Keep the scope honest -- Create exactly one `spec.create` or `spec.update` change per draft. -- Support only `spec`, `requirement`, `constraint`, and `acceptance_criterion` entities. -- Reject unsupported durable knowledge honestly. Do not silently translate architecture, conventions, patterns, Workstreams, Relays, or arbitrary Wiki pages into Specs. -- Require a clear durable claim. Do not capture unresolved brainstorming as team memory. +- Create one `knowledge.create` or `knowledge.update` change per draft, for an existing kind: `architecture`, `component`, `convention`, `decision`, `pattern`, or `guide`. +- Existing Spec workflows also support `spec.create` and `spec.update` for `spec`, `requirement`, `constraint`, and `acceptance_criterion`. Choose these only for actual Spec-family intent. +- Capture durable conclusions, their rationale, and useful evidence. Do not dump the conversation or present unresolved ideas as agreed facts. +- Do not route session logs, Relays, or routine GROW edits through Inbox merely because they contain context. ## Prepare a draft -1. Distill the durable knowledge, rationale, and useful evidence from the conversation. -2. Decide whether it creates a new Spec-family entity or updates an existing exact entity. -3. For an update, resolve the canonical target and current revisions before drafting. Never guess an ID or revision. +1. Distill what future agents or teammates need to know from the user's request and discussion. +2. Search existing knowledge first. Prefer correcting or extending the relevant record or section when it already covers the subject; create a new entry when the claim has no suitable home. +3. Read the exact target and current revisions before drafting a correction. Preserve unrelated knowledge when replacing its body. Never guess an ID or revision. 4. Preserve useful files, code, commits, entities, and external links as evidence only when actually available. Never invent provenance, authors, dates, events, or history. 5. Build one request against the action-scoped runtime contract. 6. Run the exact preview flow and summarize the human effect before technical details. diff --git a/.claude/skills/mex-inbox/agents/openai.yaml b/.claude/skills/mex-inbox/agents/openai.yaml index 9e0ac8cf..de507237 100644 --- a/.claude/skills/mex-inbox/agents/openai.yaml +++ b/.claude/skills/mex-inbox/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "MEX Inbox" - short_description: "Draft governed MEX Spec proposals" - default_prompt: "Use $mex-inbox to draft this durable requirement for MEX team review." + short_description: "Propose additions to project knowledge" + default_prompt: "Use $mex-inbox to capture what we decided as a contribution to this project's knowledge." diff --git a/.claude/skills/mex-inbox/references/cli-workflows.md b/.claude/skills/mex-inbox/references/cli-workflows.md index 76e79582..c0f9215d 100644 --- a/.claude/skills/mex-inbox/references/cli-workflows.md +++ b/.claude/skills/mex-inbox/references/cli-workflows.md @@ -23,7 +23,17 @@ Use one of these command IDs: Treat this bounded action result as the exact runtime source for the request shape, available examples, constraints, preview command, and apply command. Do not dump `mex capabilities --json` or the full Inbox contract during ordinary execution. Write request and preview JSON only to ordinary regular files inside the checkout or an approved temporary directory; do not use symlinks. -## Resolve a Spec update +## Find existing knowledge and resolve a correction + +1. Use `mex wiki query --limit 10 --json` or `mex wiki list --type --limit 25 --json` to find related records before creating another. +2. Read the best candidate with `mex inbox target --json`. This bounded read returns `target`, `version`, `sourcePath`, and the existing body from the current Wiki index, without initializing or repairing it. +3. For `knowledge.update`, copy `target` and use `version.contentHash` as the target revision and `version.semanticRevision` as the semantic revision. Select a section entity when only that section should change. The patch body replaces the target's body; preserve its relevant existing content. A target can fit the read response but exceed the 16 KiB update-body limit; choose a smaller section or a title/summary-only patch when appropriate, never truncate existing knowledge to fit. +4. If no suitable record exists, use `knowledge.create` with the appropriate existing kind. MEX chooses a path in `context/` or `patterns/`; do not invent an Inbox knowledge category or supply an arbitrary destination path. +5. If several targets remain plausible after reading them, ask which one the user intends. If a read reports a stale or unavailable index, address its explicit maintenance requirement before relying on it; never fabricate revisions or silently refresh an index as part of a read. + +For create-time topics, find them with Wiki reads, then resolve each with `mex inbox target --json` for current revisions. Topics can be dependencies but are not Inbox correction targets. Omit topics when none are needed; normal knowledge creates have no relation editor. + +## Resolve a legacy Spec update 1. Use `mex spec list --json` to identify candidates. 2. Use `mex spec show --json` for the exact candidate. @@ -36,7 +46,7 @@ Do not invent target IDs, relation endpoints, topic IDs, or revisions. For a cre ## Save a checkout-local draft 1. Resolve `inbox.draft.save`. -2. Create a unique operation ID and a request containing one `spec.create` or `spec.update` draft. +2. Create a unique operation ID and a request containing one `knowledge.create` or `knowledge.update` draft (or a Spec change for actual Spec-family intent). 3. For a new draft, provide no unrelated expectations. For an existing draft update, read it with `mex inbox draft show --json` and use its exact current local revision. 4. Preview with `mex inbox draft save --json` and capture the complete successful JSON wrapper unchanged. Require `ok: true`, `mode: "preview"`, and `data.preview.valid: true`. 5. Summarize the proposed local effect. If the user asked to create/save/draft, apply with `mex inbox draft save --apply --json` without another confirmation. @@ -60,7 +70,7 @@ The apply writes only checkout-local draft state. It does not create a canonical 5. Apply the exact preview with `mex inbox publish --apply --json`. 6. Return `/inbox?view=review&proposal=`. -Publishing removes the exact local draft after creating the pending proposal. It does not approve the proposal or write the requested Spec change. +Publishing removes the exact local draft after creating the pending proposal. It does not approve the proposal or change accepted knowledge. The proposal is Markdown in the working tree; teammates receive it through Git. ## Review canonical proposals @@ -73,4 +83,4 @@ Use `mex inbox proposal list --json` and `mex inbox proposal show 5. Wait for fresh explicit confirmation. 6. Apply the exact preview with the same command plus `--apply --json`. -Approval writes the proposed Spec-family entity change, proposal decision, Wiki ledger, and Activity records to the working tree. Reject and withdraw make a terminal proposal decision without changing the Spec. Mark stale changes a pending proposal to stale only when MEX proves dependency drift. Repair replaces stale intent, clears prior review, and returns the proposal to pending without changing the Spec. These canonical transitions write Activity records; none commits, pushes, pulls, stages, or notifies teammates. +Approval writes the proposed knowledge change, proposal decision, Wiki ledger, and Activity records to the working tree. The proposal remains review history. Reject and withdraw make a terminal proposal decision without changing knowledge. Mark stale changes a pending proposal to stale only when MEX proves dependency drift. Repair replaces stale intent, clears prior review, and returns the proposal to pending without changing knowledge. These canonical transitions write Activity records; none commits, pushes, pulls, stages, or notifies teammates. diff --git a/.mex/ROUTER.md b/.mex/ROUTER.md index cb5e9c7e..01b498f1 100644 --- a/.mex/ROUTER.md +++ b/.mex/ROUTER.md @@ -88,6 +88,17 @@ Then read this file fully before doing anything else in this session. navigation now emphasize Context, Code, Relays, and Activity while legacy workflow routes remain readable. Local verification is recorded in the same release plan; this is local implementation, not a published release. +- Phase 2b extends Inbox into an explicit contribution workflow for existing + Wiki knowledge: architecture, component, convention, decision, pattern, and + guide additions or text corrections, including existing section entities. + Local drafts publish as Markdown proposals; approval writes existing + `context/` or `patterns/` knowledge and carries the proposal source/evidence. + Original attribution and grounding survive corrections. Legacy Spec payloads + and signed recovery remain supported; ordinary GROW upkeep remains direct. + Inbox and its review count are restored in primary navigation; Team sits with + Relays/Activity. The agent skill searches existing knowledge and uses the + fresh, bounded `mex inbox target --json` lookup for exact correction + revisions. This is working-tree implementation, not a published release. - Explicit graph status, refresh, and isolated rebuild/recovery commands preserve the last trustworthy index behind one cross-process maintenance lease. - Targeted graph get/query/impact consumers use one provenance-bound immutable diff --git a/.mex/patterns/local-first-team-state.md b/.mex/patterns/local-first-team-state.md index d59eb6f3..3b1c516a 100644 --- a/.mex/patterns/local-first-team-state.md +++ b/.mex/patterns/local-first-team-state.md @@ -12,12 +12,12 @@ edges: condition: "when connecting team state to Hub, Wiki, or graph consumers" - target: "context/conventions.md" condition: "when changing canonical serialization or validation" -last_updated: 2026-09-03 +last_updated: 2026-09-08 mex: id: mx_01M1M0CJMRWZY5TZCEBSFJPAHT type: pattern status: promoted - revision: 4 + revision: 5 title: local-first-team-state grounds_to: - node: function:ecf1fb45ac2910d02bc78f6f761c0145 @@ -109,6 +109,18 @@ under `.mex/local/`. When present, the legacy decision-event JSONL stays byte-fo - Canonical handoff identity comparisons use stable Member IDs. Display names, Git aliases, and serialized actor objects are snapshots for review, not authorization keys. +- An additive Inbox payload must preserve legacy materialization bytes: changing + old approval serialization can invalidate an already signed preview or its + interrupted-write recovery. New contribution attribution must also use stable + object-field order because receipt decoding may reorder JSON keys before + canonical YAML is rendered. +- Inbox proposals are review artifacts, not a Wiki knowledge category. Apply + corrections to existing entities and append proposal/evidence sources while + retaining original producer attribution and grounding baselines. Routine + non-Spec Wiki/GROW upkeep does not require Inbox. +- A stable Wiki read can represent an already stale index. Target discovery for + a correction must require fresh status in the same immutable observation as + the returned text and revisions; a separate earlier status check is not enough. ## Verify diff --git a/AGENTS.md b/AGENTS.md index c09cc92f..0f7e88d4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ ## MEX agent skills - At the start of every session, read `.mex/AGENTS.md` and `.mex/ROUTER.md` before project work; follow `ROUTER.md` to load only the relevant context. -- Use `$mex-inbox` for durable governed Spec proposals and `$mex-relay` for durable team handoffs. Invoke them automatically when intent clearly matches; explicit invocation remains available. +- Use `$mex-inbox` for explicit contributions to project knowledge and `$mex-relay` for durable team handoffs. Invoke them automatically when intent clearly matches; ordinary GROW upkeep remains available without Inbox. - When MEX context materially influences an answer or implementation, include one concise acknowledgement: `MEX context used: .` - Do not claim an author, date, or historical event unless the retrieved data actually provides it. - After a MEX write, say exactly what changed and its sharing boundary: a local draft is checkout-only and nothing is shared; a canonical artifact is written to the working tree and requires commit/push to share. diff --git a/CLAUDE.md b/CLAUDE.md index b71c2c81..59b433c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ ## MEX agent skills - At the start of every session, read `.mex/AGENTS.md` and `.mex/ROUTER.md` before project work; follow `ROUTER.md` to load only the relevant context. -- Use `/mex-inbox` for durable governed Spec proposals and `/mex-relay` for durable team handoffs. Invoke them automatically when intent clearly matches; explicit invocation remains available. +- Use `/mex-inbox` for explicit contributions to project knowledge and `/mex-relay` for durable team handoffs. Invoke them automatically when intent clearly matches; ordinary GROW upkeep remains available without Inbox. - When MEX context materially influences an answer or implementation, include one concise acknowledgement: `MEX context used: .` - Do not claim an author, date, or historical event unless the retrieved data actually provides it. - After a MEX write, say exactly what changed and its sharing boundary: a local draft is checkout-only and nothing is shared; a canonical artifact is written to the working tree and requires commit/push to share. diff --git a/README.md b/README.md index d010d043..ea4fdb1f 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ The Hub is where people explore and review their team's memory. Open it to under ![Explore Wiki and Code, review Inbox and Specs, and coordinate Relays and Team members in the local Project Hub.](docs/diagrams/readme/hub.svg) - **Understand the project:** Overview, Search, Knowledge, Specs, and Code bring explanations and implementation evidence together. -- **Review and carry work forward:** Inbox supports governed Spec proposals; Relays preserve what the next person needs; Workstreams retain the surrounding context. +- **Review and carry work forward:** Inbox proposes additions and corrections to project knowledge; Relays preserve what the next person needs. Existing Spec proposals and Workstream records remain readable. - **See who and what:** Team/Members supports attribution and local identity selection. Activity shows accepted MEX workflow events and recorded project notes—not every code edit or Git action. - **Keep context usable:** Health and Jobs expose index status and explicit maintenance. @@ -221,7 +221,7 @@ Drift is a review signal. It does **not** prove that prose is false, that a code ## Agents help maintain the team's memory -Agents are both readers and contributors: they can retrieve the team's existing context, help capture discoveries from real work, and prepare Spec proposals or handoffs for a person to review. They do not independently decide what should be published or shared. +Agents are both readers and contributors: they can retrieve the team's existing context, help capture discoveries from real work, and prepare knowledge proposals or handoffs for a person to review. They do not independently decide what should be published or shared. Setup installs small host-agent instructions that point to `.mex/AGENTS.md` for policy and `.mex/ROUTER.md` for task-relevant context. Agents can query Wiki and Graph evidence, provided the host follows those instructions. @@ -244,7 +244,9 @@ Use `--tool claude` for Claude Code. Review the resulting instruction and skill Instructions may select Inbox or Relay from clear natural-language intent, but skill activation never approves a canonical write. When MEX context materially informs work, the agent names the records used; this is transparency, not proof of reasoning. -The governed Inbox path applies to Spec-family proposals. Ordinary Wiki and context updates do not all pass through Inbox; review those working-tree changes through your normal engineering workflow. +With the 0.8.1 Inbox update, “use MEX Inbox to capture what we decided” produces a contribution to existing project knowledge. The agent checks existing records, then drafts one addition or correction. Architecture, components, conventions, decisions, patterns, and guides are supported alongside existing Spec proposals. A local draft stays in the checkout; publishing writes a Markdown proposal for review; approval updates canonical knowledge and retains the proposal as history. Git shares those files with teammates. + +Ordinary GROW, Wiki, and context upkeep remains available without Inbox. Inbox is the explicit contribution path, not another knowledge category.

@@ -260,7 +262,7 @@ The repository includes an [MCP workspace](https://github.com/mex-memory/mex/tre | --- | --- | | Search and retrieve Wiki or Graph evidence | Whether retrieved evidence is sufficient | | Create a checkout-local Inbox draft | Publishing the proposal for repository review | -| Preview a bounded Spec create/update operation | Approving or rejecting the proposed canonical change | +| Preview a bounded knowledge addition or correction | Approving or rejecting the proposed canonical change | | Create a checkout-local Relay draft | Publishing, taking, and closing a handoff | | Suggest context and grounding updates | Reviewing and committing working-tree changes | diff --git a/docs/design/0.8.1-release-plan.md b/docs/design/0.8.1-release-plan.md index aea660e0..c1f82ddc 100644 --- a/docs/design/0.8.1-release-plan.md +++ b/docs/design/0.8.1-release-plan.md @@ -1,7 +1,8 @@ # MEX 0.8.1 release plan -Status: Phases 1 and 2 implemented and locally verified. -Implementation of later phases has not started. +Status: Phases 1, 2, and 2b implemented and locally verified. +Current local commit checkpoint includes Phase 2b (Inbox knowledge contributions); +later phases have not started. Branch: `codex/0.8.1`, starting from `4942489`. ## Release intent @@ -11,8 +12,8 @@ small team: visual repository context, practical Relays, and trustworthy grounding. Reuse the current engines and contracts. Keep telemetry as a separate final change, and isolate Windows changes so their effects can be reviewed. -Implementation, local verification, and committing the completed Phases 1–2 -are authorized. Push, release publication, and telemetry delivery remain outside +Phases 1–2 were committed locally. Phase 2b is included in the next authorized +local commit. Push, release publication, and telemetry delivery remain outside this checkpoint. ## Phases @@ -20,7 +21,8 @@ this checkpoint. | Phase | Scope | Done when | Status | | --- | --- | --- | --- | | 1. Grounding safety | Remove agent-exit-driven baseline renewal; preserve old evidence; make acceptance explicit and scoped; retain initial capture; keep moved-symbol repair from accepting changed behavior. | No-op agents cannot clear drift; explicit acceptance affects only reviewed entries; setup, legacy grounding, moved symbols, and index rebuild remain covered. | Locally verified | -| 2. Context-focused Hub | Show all knowledge entities in a graph-first Context view, organized by type, with direct code groundings expanding on selection and details in a sidebar. Retain search/filters and a list alternative. Simplify navigation and retire Specs/Workstreams/Spec-only Inbox from the primary experience. | The usual 25–35 entities are visible together, including unlinked sections; recorded relationships and code groundings are useful to explore; old artifacts and links remain readable; route and resource budgets hold. | Locally verified | +| 2. Context-focused Hub | Show all knowledge entities in a graph-first Context view, organized by type, with direct code groundings expanding on selection and details in a sidebar. Retain search/filters and a list alternative. Simplify navigation and retire Specs/Workstreams from the primary experience. | The usual 25–35 entities are visible together, including unlinked sections; recorded relationships and code groundings are useful to explore; old artifacts and links remain readable; route and resource budgets hold. | Locally verified | +| 2b. Inbox knowledge contributions | Restore Inbox in navigation; let agents or people propose one addition/correction to existing project knowledge, reuse review/publication, retain evidence, and keep legacy Specs compatible. | A discussion can become a local draft, a Git-shareable Markdown proposal, and an explicitly approved change to existing Wiki knowledge; ordinary GROW upkeep remains available. | Locally verified | | 3. Practical Relays | Open-to-team audience including future active Members; drafts without recipients; shorter agent/CLI saving; persistent sharing and claim-eligibility information; inactive-member recovery. | An engineer can save context now and an eligible teammate can take it later; local publication is never presented as verified delivery. | Not started | | 4. Focused corrections and knowledge reuse | Unknown-file migration classification, contribution/evidence provenance, confirmed fresh-install bugs, configurable agent logging and relevant log retrieval, docs/translations. | Identified defects are fixed; logging policy is understandable; prior notes can inform work without treating every note as accepted knowledge. | Not started | | 5. Windows hardening | Two independently reviewable changes: narrow CRLF normalization, then preserve full-width inode identity in affected paths. | Content/revision, preview/recovery, replacement, and lock checks pass, including real Windows coverage. | Not started | @@ -131,7 +133,8 @@ Wiki revision itself stays unchanged. Home and primary navigation now emphasize Context, Code, Relays, and Activity. Specs, Workstreams, and Spec-only Inbox have left the primary navigation; their -existing artifacts and direct routes remain readable. +existing artifacts and direct routes remain readable. The subsequent Phase 2b +restores Inbox as the explicit contribution path for project knowledge. Local verification: @@ -167,6 +170,90 @@ Windows checks remain release gates. The Knowledge read benchmark now targets runtime budgets remain unchanged and are not claimed to pass from local timing. Phases 3–6 remain unstarted. +## Phase 2b: explicit knowledge contributions + +Inbox remains a core team feature. It is a contribution workflow into existing +knowledge, with proposals retained as review history. It does not create a new +knowledge category or become mandatory for ordinary GROW/context upkeep. + +- Start from the real request: “capture what we decided in project knowledge.” + Distill durable conclusions and supporting evidence, search existing records, + and prefer a correction or extension when the subject already has a home. +- Reuse checkout-local drafts, portable Markdown proposals, exact signed + preview/apply, review decisions, stale/repair handling, and interrupted-write + recovery. Keep one entity per proposal. +- Add `knowledge.create` and `knowledge.update` for architecture, component, + convention, decision, pattern, and guide. Corrections change title, summary, + or body on an exact existing entity, including a section. New patterns use + `patterns/`; other new knowledge uses `context/`. There is no arbitrary path, + type-conversion, bulk-edit, or new relationship editor. +- Keep existing `spec.create`/`spec.update` proposals readable and reviewable + with their original stored format. Add knowledge support rather than rewrite + old artifacts or broaden the Spec-only direct-write guard. +- Preserve contribution evidence and a link back to the proposal in approved + knowledge. Preserve original attribution and grounding on corrections; do + not infer a producer from a reviewer or accept new grounding baselines. +- Make the sharing stages explicit: a local draft is checkout-only; publishing + writes a pending Markdown proposal into the working tree; approval changes + canonical knowledge. Git distributes canonical files; MEX does not prove + delivery to another checkout. +- Restore Inbox and its pending count in the sidebar, put Team alongside + Relays/Activity, and retain the existing dashboard theme. Update the packaged + Inbox skill and managed instructions for fresh and existing installations. +- Let agents use bounded Wiki search plus `mex inbox target --json` to + obtain existing text and exact revision expectations for a correction. + +This is a bounded extension of the current workflow. Relays, logging settings, +Windows changes, and telemetry remain separate phases. + +### Phase 2b result + +Inbox now accepts one knowledge addition or text correction through the existing +draft, publication, and review flow. The Hub composer supports all six ordinary +knowledge kinds and exact document or section targets. Existing Spec drafts, +proposals, signed envelopes, and recovery remain compatible. Inbox and its review +count are back in primary navigation, with Team beside Relays and Activity. + +Approved knowledge retains the proposal link and supplied evidence. Corrections +preserve original attribution, neighboring sections, and grounding baselines. +The new `mex inbox target` read returns existing text and exact containing-file +revisions from a fresh Wiki observation, with an allowlisted 64 KiB response +limit and no implicit index maintenance. Packaged and installed Inbox skills now +search existing knowledge before drafting a contribution; ordinary GROW upkeep +remains available directly. + +Local verification: + +- All 59 real Inbox contract cases passed across focused runs, including + legacy Spec behavior, each knowledge kind, stale/repair, containment, and + interrupted approval recovery. Initial failures were timeout-only under + concurrent load. Two older aggregate tests were split into seven independent + parameterized cases with identical assertions and unchanged timeouts. +- All 173 focused Wiki writer/model/adapter tests and 17 knowledge safety tests + passed. CLI target tests cover exact hashes, fresh read-only observations, + absent or invalid targets, metadata filtering, and serialized response bounds. +- All 414 Hub tests passed with one worker. Shared contracts, Hub services, + capabilities/schema parity, managed instructions, installer, and skill content + checks passed. No timeouts or resource budgets were widened. +- 27 distinct focused browser checks passed across runs, including local draft + creation, legacy draft editing/publication, review states, responsive layouts, + keyboard navigation, and accessibility. Eleven affected macOS screenshots + were refreshed and visually reviewed; the final Search readiness check passed. +- Final root and workspace typechecks passed. Full `npm run build`, the final + `build:hub`, and the packed fresh-install Hub/official-skills smoke test passed. + Graph evaluator and protocol behavior were unchanged, so evaluator checks + were not applicable to this phase. +- Existing asset budgets pass unchanged: initial JavaScript is 463,641 bytes + and CSS 70,574 bytes; the lazy Inbox route adds 81,140 JavaScript bytes and + 15,454 CSS bytes. Deferred workbenches remain outside Home/shell closures. +- Public package exports and dependencies are unchanged. `git diff --check` + passes; generated indexes, local state, and built output are excluded. + +This phase is included in the local commit checkpoint, including managed skill +and MEX context updates. Nothing has been pushed. Test servers are stopped. +Pinned Ubuntu runtime/heap gates and real Windows coverage remain release +requirements. Phase 3 is next; telemetry stays last and separate. + ## Logging addition `mex log` currently appends notes/decisions/risks/todos to diff --git a/docs/design/inbox-spec-authoring-contract.md b/docs/design/inbox-spec-authoring-contract.md index 17270038..c06224f1 100644 --- a/docs/design/inbox-spec-authoring-contract.md +++ b/docs/design/inbox-spec-authoring-contract.md @@ -1,5 +1,44 @@ # Inbox-Governed Spec Authoring Contract +> **0.8.1 extension:** Inbox also accepts explicit contributions to existing +> project knowledge. The additive contract below supersedes the Spec-only +> product scope; the original Spec format and its safety rules remain supported. + +## 0.8.1 knowledge contributions + +Inbox is the deliberate proposal/review path into canonical Wiki knowledge. +It adds no knowledge category and does not require routine GROW or ordinary +non-Spec Wiki upkeep to go through review. + +- `knowledge.create` accepts `entityKind` (architecture, component, convention, + decision, pattern, guide), title, body, optional summary/topics, and status + (`in_flight` or `promoted`). MEX mints the ID and path: patterns use + `patterns/.md`; other kinds use `context/-.md`. +- `knowledge.update` accepts one exact `target` (id, kind, optional title) and a + nonempty `patch` of title, summary, or body. A target can be an existing + document or section. The existing dependency revision rules apply. +- Knowledge creates have no relation editor. The closed legacy Spec relation + rules below still apply to existing Spec workflows. +- New knowledge requests use `mex.team.inbox.knowledge-change.v1`; existing + `mex.team.inbox.spec-change.v1` bytes are not migrated. The compatibility-named + private types, receipt domain, and `spec-entity` minted-ID receipt purpose are + retained for both create families. These are implementation tokens, not UI + categories. +- Approval carries a proposal source link and captured evidence into knowledge; + corrections append sources while retaining prior attribution and grounding. + Publication-time author and reviewer remain distinct in proposal history. +- The Inbox skill searches existing Wiki records before creating a duplicate. + `mex inbox target --json` provides a bounded immutable projection + of target text and exact `version.contentHash`/`semanticRevision` values. +- Local drafts are checkout-only. Publishing creates proposal Markdown in the + working tree. Approval writes canonical knowledge and review/audit artifacts. + Commit/push/pull remain the Git sharing steps. + +Existing bounds, exact preview/apply, containment, stale/repair, recovery, and +legacy Spec guards below continue to apply. The default Hub composer now uses +knowledge contributions, while older Spec drafts and proposals retain their +original review path. + Status: Checkpoints E1-E4 implemented; pinned calibration applied and enforcing CI required This brief freezes the minimum product boundary for checkout-local Inbox drafts, diff --git a/packages/hub-contracts/src/inbox-knowledge.test.ts b/packages/hub-contracts/src/inbox-knowledge.test.ts new file mode 100644 index 00000000..0544ceda --- /dev/null +++ b/packages/hub-contracts/src/inbox-knowledge.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; +import { InboxDraftInputSchema, InboxKnowledgeKindSchema, InboxProposalSummarySchema } from "./index.js"; + +const id = "mx_01000000000000000000000001"; +const draft = { + change: { kind: "knowledge.create", entityKind: "pattern", title: "Preserve reviewed evidence", body: "Keep the accepted baseline until review.", status: "in_flight" }, + rationale: "An automatic refresh must not erase drift.", evidence: [], targetRevisions: [], +}; + +describe("private Hub knowledge Inbox contracts", () => { + it.each(InboxKnowledgeKindSchema.options)("accepts one %s create with unchanged canonical text", (entityKind) => { + const input = { ...draft, change: { ...draft.change, entityKind, summary: "", body: "First line\n\tSecond line" } }; + expect(InboxDraftInputSchema.parse(input)).toEqual(input); + }); + + it("retains the legacy Spec discriminators and rejects crossed kinds or knowledge hierarchy edits", () => { + expect(InboxDraftInputSchema.safeParse({ ...draft, change: { ...draft.change, kind: "spec.create", entityKind: "spec" } }).success).toBe(true); + for (const change of [ + { ...draft.change, entityKind: "spec" }, + { ...draft.change, kind: "spec.create" }, + { ...draft.change, relation: { type: "related_to", target: { id, kind: "pattern" } } }, + ]) expect(InboxDraftInputSchema.safeParse({ ...draft, change }).success).toBe(false); + }); + + it("requires exact target coverage and keeps explicit summary clearing distinct from an empty update", () => { + const input = { ...draft, + change: { kind: "knowledge.update", target: { id, kind: "architecture" }, patch: { summary: "" } }, + targetRevisions: [{ target: { kind: "entity", id }, revision: "a".repeat(64), semanticRevision: 3 }], + }; + expect(InboxDraftInputSchema.parse(input)).toEqual(input); + expect(InboxDraftInputSchema.safeParse({ ...input, targetRevisions: [] }).success).toBe(false); + expect(InboxDraftInputSchema.safeParse({ ...input, targetRevisions: [...input.targetRevisions, ...input.targetRevisions] }).success).toBe(false); + expect(InboxDraftInputSchema.safeParse({ ...input, change: { ...input.change, patch: {} } }).success).toBe(false); + expect(InboxDraftInputSchema.safeParse({ ...input, change: { ...input.change, patch: { status: "promoted" } } }).success).toBe(false); + }); + + it("allows knowledge summaries without changing proposal identity or review authority rules", () => { + const proposalId = "proposal_01000000000000000000001720"; + const summary = { + schemaVersion: 1, ref: { id: proposalId, kind: "proposal" }, sourcePath: `.mex/inbox/${proposalId}.md`, + revision: "b".repeat(64), state: "pending", author: { kind: "unknown" }, + changeKind: "knowledge.update", entityKind: "guide", title: "Setup guide", rationaleExcerpt: "Clarify installation.", + }; + expect(InboxProposalSummarySchema.safeParse(summary).success).toBe(true); + expect(InboxProposalSummarySchema.safeParse({ ...summary, state: "approved" }).success).toBe(false); + }); +}); diff --git a/packages/hub-contracts/src/index.ts b/packages/hub-contracts/src/index.ts index 5812da86..8147414b 100644 --- a/packages/hub-contracts/src/index.ts +++ b/packages/hub-contracts/src/index.ts @@ -837,6 +837,12 @@ export const InboxSpecKindSchema = z.enum([ "acceptance_criterion", ]); +export const InboxKnowledgeKindSchema = z.enum([ + "architecture", "component", "convention", "decision", "pattern", "guide", +]); +export const InboxEntityKindSchema = z.union([InboxKnowledgeKindSchema, InboxSpecKindSchema]); +const inboxChangeKind = z.enum(["spec.create", "spec.update", "knowledge.create", "knowledge.update"]); + export const InboxProposalStateSchema = z.enum([ "pending", "approved", @@ -950,9 +956,23 @@ export const InboxSpecUpdateChangeSchema = z.object({ patch: inboxSpecUpdatePatch, }).strict(); +export const InboxKnowledgeCreateChangeSchema = inboxSpecCreateChangeObject + .omit({ relation: true }) + .extend({ kind: z.literal("knowledge.create"), entityKind: InboxKnowledgeKindSchema }) + .strict(); + +export const InboxKnowledgeUpdateChangeSchema = z.object({ + kind: z.literal("knowledge.update"), + target: inboxSpecRef.extend({ kind: InboxKnowledgeKindSchema }), + patch: inboxSpecUpdatePatch, +}).strict(); + +// Compatibility name: existing Spec envelopes retain their exact discriminators. export const InboxSpecChangeSchema = z.union([ InboxSpecCreateChangeSchema, InboxSpecUpdateChangeSchema, + InboxKnowledgeCreateChangeSchema, + InboxKnowledgeUpdateChangeSchema, ]); const inboxEntityRevisionExpectation = z.object({ @@ -1014,10 +1034,10 @@ export const InboxEvidenceRefSchema = z.discriminatedUnion("kind", [ ]); function inboxSpecDependencyIds(change: z.infer): string[] { - if (change.kind === "spec.update") return [change.target.id]; + if (change.kind === "spec.update" || change.kind === "knowledge.update") return [change.target.id]; return [...new Set([ ...(change.topics ?? []), - ...(change.relation ? [change.relation.target.id] : []), + ...(change.kind === "spec.create" && change.relation ? [change.relation.target.id] : []), ])].sort(); } @@ -1036,7 +1056,7 @@ function validateInboxDependencyCoverage( context.addIssue({ code: z.ZodIssueCode.custom, path: ["targetRevisions"], - message: "Exact revisions must cover every Spec dependency once.", + message: "Exact revisions must cover every knowledge dependency once.", }); } } @@ -1060,8 +1080,8 @@ export const InboxDraftSummarySchema = z.object({ id: InboxDraftIdSchema, revision, updatedAt: isoTimestamp, - changeKind: z.enum(["spec.create", "spec.update"]), - entityKind: InboxSpecKindSchema, + changeKind: inboxChangeKind, + entityKind: InboxEntityKindSchema, title: inboxText(512), rationaleExcerpt: utf8Text(240), }).strict(); @@ -1083,8 +1103,8 @@ const inboxProposalSummaryObject = z.object({ revision, state: InboxProposalStateSchema, author: TeamActorRefSchema, - changeKind: z.enum(["spec.create", "spec.update"]), - entityKind: InboxSpecKindSchema, + changeKind: inboxChangeKind, + entityKind: InboxEntityKindSchema, title: inboxText(512), rationaleExcerpt: utf8Text(240), reviewer: TeamActorRefSchema.optional(), @@ -3211,6 +3231,10 @@ export type TeamOperationApplyRequest = z.infer; export type TeamOperationApplyResponse = z.infer; export type InboxSpecKind = z.infer; +export type InboxKnowledgeKind = z.infer; +export type InboxEntityKind = z.infer; +export type InboxKnowledgeCreateChange = z.infer; +export type InboxKnowledgeUpdateChange = z.infer; export type InboxProposalState = z.infer; export type InboxDraftId = z.infer; export type InboxProposalId = z.infer; diff --git a/packages/hub-web/src/api/types.ts b/packages/hub-web/src/api/types.ts index 1056d2f1..fff1fc6f 100644 --- a/packages/hub-web/src/api/types.ts +++ b/packages/hub-web/src/api/types.ts @@ -51,6 +51,8 @@ export type { InboxProposalSummary, InboxSpecChange, InboxSpecKind, + InboxKnowledgeKind, + InboxEntityKind, RelayDetail, RelayDraftDetail, RelayDraftInput, diff --git a/packages/hub-web/src/app/App.test.tsx b/packages/hub-web/src/app/App.test.tsx index 261e6e74..16ecc38d 100644 --- a/packages/hub-web/src/app/App.test.tsx +++ b/packages/hub-web/src/app/App.test.tsx @@ -70,28 +70,27 @@ describe("Project Hub routes", () => { "Overview", "Context", "Code", + "Inbox", "Relays", "Activity", + "Team", ]); - expect(within(primary).getByRole("region", { name: "Project Memory" })).toHaveTextContent( + expect(within(primary).getByRole("region", { name: "Project" })).toHaveTextContent( "ContextCode", ); expect(within(within(primary).getByRole("region", { name: "Teamwork" })) .getAllByRole("link") .map((link) => link.querySelector("span")?.textContent)) - .toEqual(["Relays", "Activity"]); + .toEqual(["Relays", "Activity", "Team"]); expect(within(primary).queryByRole("region", { name: "Coming Soon" })).not.toBeInTheDocument(); - for (const label of ["Specs", "Workstreams", "Inbox", "Playbooks", "Catch Up"]) { + for (const label of ["Specs", "Workstreams", "Playbooks", "Catch Up"]) { expect(within(primary).queryByRole("link", { name: new RegExp(`^${label}`, "u") })).not.toBeInTheDocument(); } const utilities = within(sidebar).getByRole("navigation", { name: "Project utilities" }); - expect(within(utilities).getAllByRole("link").map((link) => link.textContent)).toEqual([ - "Team", - ]); + expect(within(utilities).queryAllByRole("link")).toEqual([]); await user.click(within(utilities).getByRole("button", { name: /^System/u })); expect(within(utilities).getAllByRole("link").map((link) => link.querySelector("span")?.textContent)).toEqual([ - "Team", "Health", "Jobs", ]); @@ -102,7 +101,7 @@ describe("Project Hub routes", () => { const first = renderRoute("/"); await screen.findByRole("heading", { level: 1, name: fixtureOverviewHeading }); - const projectMemory = screen.getByRole("button", { name: "Project Memory" }); + const projectMemory = screen.getByRole("button", { name: "Project" }); const teamwork = screen.getByRole("button", { name: "Teamwork" }); const system = screen.getByRole("button", { name: /^System/u }); expect(projectMemory).toHaveAttribute("aria-expanded", "true"); @@ -118,14 +117,14 @@ describe("Project Hub routes", () => { first.unmount(); renderRoute("/"); await screen.findByRole("heading", { level: 1, name: fixtureOverviewHeading }); - expect(screen.getByRole("button", { name: "Project Memory" })).toHaveAttribute("aria-expanded", "true"); + expect(screen.getByRole("button", { name: "Project" })).toHaveAttribute("aria-expanded", "true"); expect(screen.getByRole("button", { name: "Teamwork" })).toHaveAttribute("aria-expanded", "true"); expect(screen.getByRole("button", { name: /^System/u })).toHaveAttribute("aria-expanded", "false"); }); it.each([ - ["/knowledge/mx_01K36WVM6H7JK8M9NPQRSTVVWX", "Project Memory", "Context"], - ["/code/symbols/sym.createHubServer", "Project Memory", "Code"], + ["/knowledge/mx_01K36WVM6H7JK8M9NPQRSTVVWX", "Project", "Context"], + ["/code/symbols/sym.createHubServer", "Project", "Code"], ["/jobs", "System", "Jobs"], ])("opens the active group and marks its nested route for %s", async (route, group, link) => { renderRoute(route); @@ -138,7 +137,7 @@ describe("Project Hub routes", () => { it("keeps a manually collapsed active group visibly active", async () => { const user = userEvent.setup(); renderRoute("/knowledge/mx_01K36WVM6H7JK8M9NPQRSTVVWX"); - const disclosure = await screen.findByRole("button", { name: "Project Memory" }); + const disclosure = await screen.findByRole("button", { name: "Project" }); await user.click(disclosure); expect(disclosure).toHaveAttribute("aria-expanded", "false"); expect(disclosure).toHaveAttribute("data-active", "true"); @@ -448,7 +447,7 @@ describe("Project Hub routes", () => { expect(screen.getByRole("link", { name: "Activity" })).toBeVisible(); expect(screen.getByRole("link", { name: "Team" })).toHaveAttribute("href", "/members"); - expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: /^Inbox/u })).toHaveAttribute("href", "/inbox"); expect(screen.getByRole("link", { name: /^Relays/u })).toHaveAttribute("href", "/relays"); expect(screen.queryByRole("region", { name: "Project sections" })).not.toBeInTheDocument(); expect(screen.queryByRole("heading", { name: "Recent jobs" })).not.toBeInTheDocument(); diff --git a/packages/hub-web/src/app/HubSidebar.test.tsx b/packages/hub-web/src/app/HubSidebar.test.tsx index f695bf4b..a370d3d6 100644 --- a/packages/hub-web/src/app/HubSidebar.test.tsx +++ b/packages/hub-web/src/app/HubSidebar.test.tsx @@ -49,10 +49,11 @@ describe("HubSidebar dynamic state", () => { const { capabilities, home } = await fixtureData(); renderSidebar({ capabilities, home: homeWithCounts(home, count) }); - expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: /^Inbox/u })).toBeVisible(); const relays = screen.getByRole("link", { name: /^Relays/u }); const system = screen.getByRole("button", { name: /^System/u }); const cases = [ + [screen.getByRole("link", { name: /^Inbox/u }), `${count} proposals for team review.`], [relays, `${count} open Relays for you.`], [system, `${count} active system operations.`], ] as const; @@ -71,7 +72,7 @@ describe("HubSidebar dynamic state", () => { const { capabilities, home } = await fixtureData(); const first = renderSidebar({ capabilities }); - expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: /^Inbox/u })).toBeVisible(); expect(screen.getByRole("link", { name: "Relays" })).toBeVisible(); expect(screen.getByRole("button", { name: "System" })).toBeVisible(); expect(screen.getByText("Set team identity")).toBeVisible(); @@ -88,7 +89,7 @@ describe("HubSidebar dynamic state", () => { }, }); - expect(screen.queryByRole("link", { name: /^Inbox/u })).not.toBeInTheDocument(); + expect(screen.getByRole("link", { name: /^Inbox/u })).toBeVisible(); expect(screen.getByRole("link", { name: "Relays" })).toBeVisible(); expect(screen.queryByText("Unavailable")).not.toBeInTheDocument(); }); diff --git a/packages/hub-web/src/app/HubSidebar.tsx b/packages/hub-web/src/app/HubSidebar.tsx index 0d0746a3..382f6019 100644 --- a/packages/hub-web/src/app/HubSidebar.tsx +++ b/packages/hub-web/src/app/HubSidebar.tsx @@ -30,6 +30,7 @@ type ExpansionState = Record; const LOCALITY_EXPLANATION = "MEX runs on this device. Canonical team records are shared when committed and pushed; drafts and indexes remain local to this checkout."; const countLabels: Record string> = { + inbox: (count) => `${count} proposals for team review.`, relays: (count) => `${count} open Relays for you.`, "active-jobs": (count) => `${count} active system operations.`, }; @@ -74,6 +75,11 @@ function countBadge(count: number | undefined, source: NavigationCountSource): R function itemCount(home: HomeResponse | undefined, item: NavigationItem): number | undefined { if (!home || !item.countSource) return undefined; + if (item.countSource === "inbox") { + return home.attention.inbox.availability === "available" + ? home.attention.inbox.teamReviewCount + : undefined; + } if (item.countSource === "relays") { return home.attention.relays.availability === "available" ? home.attention.relays.readyToTakeCount + home.attention.relays.inYourHandsCount @@ -164,6 +170,7 @@ function NavigationList({ {items.map((item) => (
  • + {item.id === "team" ? {identityText(home)} : null}
  • ))} diff --git a/packages/hub-web/src/app/inbox-knowledge.test.tsx b/packages/hub-web/src/app/inbox-knowledge.test.tsx new file mode 100644 index 00000000..a3984ad9 --- /dev/null +++ b/packages/hub-web/src/app/inbox-knowledge.test.tsx @@ -0,0 +1,119 @@ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { MemoryRouter } from "react-router-dom"; +import { describe, expect, it, vi } from "vitest"; +import type { HubApi } from "../api/client"; +import { HubApiProvider } from "../api/context"; +import type { InboxOperationPreviewResponse, WikiEntityDetailResponse } from "../api/types"; +import { createFixtureApi } from "../dev/fixture-api"; +import { AppRoutes } from "./App"; + +function mount(api: HubApi, route = "/inbox?view=drafts") { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } }); + render( + + ); + return queryClient; +} + +async function createDialog(user: ReturnType) { + await user.click(await screen.findByRole("button", { name: "Create manually" })); + return screen.findByRole("dialog", { name: "Create local knowledge draft" }); +} + +describe("ordinary knowledge Inbox", () => { + it("offers the six knowledge kinds and saves one checkout-local pattern through the exact envelope", async () => { + const user = userEvent.setup(); + const api = createFixtureApi(); + const realPreview = api.previewInboxOperation.bind(api); + let envelope: InboxOperationPreviewResponse | undefined; + const preview = vi.spyOn(api, "previewInboxOperation").mockImplementation(async (request) => { + envelope = await realPreview(request); return envelope; + }); + const apply = vi.spyOn(api, "applyInboxOperation"); + mount(api); + const dialog = await createDialog(user); + expect(within(dialog).getByText(/private to this checkout/)).toBeVisible(); + const kind = within(dialog).getByRole("combobox", { name: "Knowledge kind" }); + expect(within(kind).getAllByRole("option").map((option) => option.getAttribute("value"))) + .toEqual(["architecture", "component", "convention", "decision", "pattern", "guide"]); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Title" }), { target: { value: "Preserve accepted evidence" } }); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Summary (optional)" }), { target: { value: "Review drift explicitly." } }); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Knowledge body" }), { target: { value: "Keep the old body.\n\tAccept only reviewed changes." } }); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Rationale" }), { target: { value: "Successful execution is not review." } }); + await user.click(within(dialog).getByRole("button", { name: "Advanced" })); + expect(within(dialog).queryByRole("combobox", { name: /hierarchy relation/ })).not.toBeInTheDocument(); + await user.click(within(dialog).getByRole("button", { name: "Save draft" })); + await waitFor(() => expect(apply).toHaveBeenCalledOnce()); + expect(preview.mock.calls[0]![0].action).toMatchObject({ kind: "inbox.draft.save", draft: { + change: { kind: "knowledge.create", entityKind: "pattern", title: "Preserve accepted evidence", summary: "Review drift explicitly.", body: "Keep the old body.\n\tAccept only reviewed changes." }, + rationale: "Successful execution is not review.", targetRevisions: [], + } }); + expect(apply.mock.calls[0]![0]).toBe(envelope); + expect(envelope?.preview.scope).toBe("local"); + expect(envelope?.preview.changes).toEqual([]); + expect(await screen.findByRole("heading", { level: 2, name: "Preserve accepted evidence" })).toBeVisible(); + expect(screen.getByRole("button", { name: /Preserve accepted evidence/ })).toHaveAttribute("aria-current", "true"); + }); + + it("loads an ordinary Wiki target and preserves an explicit summary-only patch with exact revisions", async () => { + const user = userEvent.setup(); + const api = createFixtureApi(); + const target = (await api.listWikiEntities({ kind: "architecture", limit: 25 })).items[0]!; + const current = await api.getWikiEntity(target.id); + const list = vi.spyOn(api, "listWikiEntities"); + const detail = vi.spyOn(api, "getWikiEntity"); + const spec = vi.spyOn(api, "getSpec"); + const specs = vi.spyOn(api, "listSpecs"); + const preview = vi.spyOn(api, "previewInboxOperation"); + mount(api); + const dialog = await createDialog(user); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Change type" }), "update"); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Knowledge kind" }), "architecture"); + await within(dialog).findByRole("option", { name: target.title }); + expect(detail).not.toHaveBeenCalled(); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Knowledge to update" }), target.id); + await waitFor(() => expect(within(dialog).getByRole("textbox", { name: "Replacement body" })).toHaveValue(current.body.content)); + expect(list).toHaveBeenCalledWith({ kind: "architecture", limit: 25 }); + expect(detail).toHaveBeenCalledWith(target.id); + expect(spec).not.toHaveBeenCalled(); expect(specs).not.toHaveBeenCalled(); + await user.click(within(dialog).getByRole("button", { name: "Body" })); + await user.click(within(dialog).getByRole("button", { name: "Summary" })); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Replacement summary" }), { target: { value: "" } }); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Rationale" }), { target: { value: "The body already carries the complete rationale." } }); + await user.click(within(dialog).getByRole("button", { name: "Save draft" })); + await waitFor(() => expect(preview).toHaveBeenCalledOnce()); + expect(preview.mock.calls[0]![0].action).toMatchObject({ kind: "inbox.draft.save", draft: { + change: { kind: "knowledge.update", target: { id: target.id, kind: "architecture", title: target.title }, patch: { summary: "" } }, + targetRevisions: [{ target: { kind: "entity", id: target.id }, revision: target.version.contentHash, semanticRevision: target.version.semanticRevision }], + } }); + }); + + it.each(["kind", "mode"])("discards a late target response after changing %s", async (change) => { + const user = userEvent.setup(); + const api = createFixtureApi(); + const target = (await api.listWikiEntities({ kind: "architecture", limit: 25 })).items[0]!; + const current = await api.getWikiEntity(target.id); + let resolve!: (value: WikiEntityDetailResponse) => void; + vi.spyOn(api, "getWikiEntity").mockImplementation(() => new Promise((done) => { resolve = done; })); + mount(api); + const dialog = await createDialog(user); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Change type" }), "update"); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Knowledge kind" }), "architecture"); + await within(dialog).findByRole("option", { name: target.title }); + await user.selectOptions(within(dialog).getByRole("combobox", { name: "Knowledge to update" }), target.id); + expect(within(dialog).getByRole("textbox", { name: "Replacement body" })).toBeDisabled(); + await user.selectOptions(within(dialog).getByRole("combobox", { name: change === "kind" ? "Knowledge kind" : "Change type" }), change === "kind" ? "guide" : "create"); + await act(async () => { resolve(current); }); + if (change === "kind") { + expect(within(dialog).getByRole("combobox", { name: "Knowledge kind" })).toHaveValue("guide"); + expect(within(dialog).getByRole("combobox", { name: "Knowledge to update" })).toHaveValue(""); + } else { + expect(within(dialog).getByRole("combobox", { name: "Change type" })).toHaveValue("create"); + expect(within(dialog).getByRole("textbox", { name: "Knowledge body" })).toHaveValue(""); + expect(within(dialog).getByRole("textbox", { name: "Knowledge body" })).toBeEnabled(); + } + expect(within(dialog).getByRole("button", { name: "Save draft" })).toBeDisabled(); + }); +}); diff --git a/packages/hub-web/src/app/inbox-page.test.tsx b/packages/hub-web/src/app/inbox-page.test.tsx index 887c426b..dc2b614a 100644 --- a/packages/hub-web/src/app/inbox-page.test.tsx +++ b/packages/hub-web/src/app/inbox-page.test.tsx @@ -238,7 +238,7 @@ describe("Inbox Spec-authoring workbench", () => { renderRoute(createFixtureApi(), `/inbox?view=review&proposal=${OWN_PROPOSAL_ID}`); const detail = await screen.findByRole("region", { name: "Selected Inbox review detail" }); - expect(await within(detail).findByText("Spec change")).toBeVisible(); + expect(await within(detail).findByText("Knowledge change")).toBeVisible(); expect(within(detail).getByText("New constraint")).toBeVisible(); expect(within(detail).getByText("Published by Ada Lovelace")).toBeVisible(); expect(within(detail).getByRole("heading", { name: "What will change" })).toBeVisible(); @@ -336,7 +336,7 @@ describe("Inbox Spec-authoring workbench", () => { renderRoute(api, `/inbox?view=review&proposal=${PROPOSAL_ID}`); const detail = await screen.findByRole("region", { name: "Selected Inbox review detail" }); - expect(await within(detail).findByText("Current Spec content could not be read")).toBeVisible(); + expect(await within(detail).findByText("Current knowledge content could not be read")).toBeVisible(); expect(within(detail).getByText(/Proposed values remain available below/)).toBeVisible(); expect(within(detail).getByText("Require exact evidence review before release approval.")).toBeVisible(); expect(within(detail).getByText(/Private proposal prose remains outside durable Specs until approval/)).toBeVisible(); @@ -450,12 +450,12 @@ describe("Inbox Spec-authoring workbench", () => { renderRoute(api); await screen.findByRole("heading", { level: 2, name: "Clarify release evidence review" }); await user.click(screen.getByRole("button", { name: "Approve change" })); - const confirmation = await screen.findByRole("alertdialog", { name: "Approve this Spec change?" }); + const confirmation = await screen.findByRole("alertdialog", { name: "Approve this knowledge change?" }); expect(within(confirmation).getByText("Clarify release evidence review")).toBeVisible(); - expect(within(confirmation).getByText("Spec entity affected")).toBeVisible(); + expect(within(confirmation).getByText("Knowledge entity affected")).toBeVisible(); expect(within(confirmation).getByText("Human-team memory release")).toBeVisible(); expect(within(confirmation).getByText("Approving as Ada Lovelace")).toBeVisible(); - expect(within(confirmation).getByText("Write the reviewed Spec change")).toBeVisible(); + expect(within(confirmation).getByText("Write the reviewed knowledge change")).toBeVisible(); expect(within(confirmation).queryByText(".mex/specs/mx_01000000000000000000000001.md")).not.toBeInTheDocument(); expect(await openExactTechnicalDetails(user, confirmation)).toBeVisible(); @@ -528,7 +528,7 @@ describe("Inbox Spec-authoring workbench", () => { expect(preview).not.toHaveBeenCalled(); await user.click(within(warning).getByRole("button", { name: "Continue without teammate review" })); - const confirmation = await screen.findByRole("alertdialog", { name: "Approve this Spec change?" }); + const confirmation = await screen.findByRole("alertdialog", { name: "Approve this knowledge change?" }); expect(preview).toHaveBeenCalledOnce(); expect(preview.mock.calls[0]![0].action).toEqual({ kind: "inbox.approve", @@ -544,7 +544,7 @@ describe("Inbox Spec-authoring workbench", () => { const gitNotice = noticeTitle.closest("[role='alert']"); if (gitNotice === null) throw new Error("Expected the focused Git truth alert."); expect(within(gitNotice).getByText( - "Spec change and review record were written to your working tree. Commit and push them to share the result with your team.", + "Knowledge change and review record were written to your working tree. Commit and push them to share the result with your team.", )).toBeVisible(); await waitFor(() => expect(gitNotice).toHaveFocus()); await user.click(within(gitNotice).getByRole("button", { name: "Dismiss Git notice" })); @@ -557,8 +557,8 @@ describe("Inbox Spec-authoring workbench", () => { await screen.findByRole("heading", { level: 2, name: "Refresh the stale review boundary" }); expect(screen.getAllByText("Needs refresh").length).toBeGreaterThan(0); - expect(screen.getByText("The referenced Spec content changed after this proposal was published.")).toBeVisible(); - expect(screen.getByText("Its author or their agent should refresh this proposal against current Spec content.")).toBeVisible(); + expect(screen.getByText("The referenced knowledge content changed after this proposal was published.")).toBeVisible(); + expect(screen.getByText("Its author or their agent should refresh this proposal against current knowledge content.")).toBeVisible(); expect(screen.queryByRole("button", { name: "Approve change" })).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: "More proposal actions" })).not.toBeInTheDocument(); expect(screen.queryByText("Repair manually…")).not.toBeInTheDocument(); @@ -727,10 +727,10 @@ describe("Inbox Spec-authoring workbench", () => { await openDrafts(user); const trigger = await screen.findByRole("button", { name: "Create manually" }); await user.click(trigger); - const dialog = await screen.findByRole("dialog", { name: "Create local Spec draft" }); + const dialog = await screen.findByRole("dialog", { name: "Create local knowledge draft" }); await waitFor(() => expect(within(dialog).getByRole("combobox", { name: "Change type" })).toHaveFocus()); const title = within(dialog).getByRole("textbox", { name: "Title" }); - const body = within(dialog).getByRole("textbox", { name: "Spec body" }); + const body = within(dialog).getByRole("textbox", { name: "Knowledge body" }); const rationale = within(dialog).getByRole("textbox", { name: "Rationale" }); fireEvent.change(title, { target: { value: "Canonical multiline requirement" } }); fireEvent.change(body, { target: { value: "First line\n\tTabbed second line" } }); @@ -824,9 +824,9 @@ describe("Inbox Spec-authoring workbench", () => { await openDrafts(user); const trigger = await screen.findByRole("button", { name: "Create manually" }); await user.click(trigger); - expect(await screen.findByRole("dialog", { name: "Create local Spec draft" })).toBeVisible(); + expect(await screen.findByRole("dialog", { name: "Create local knowledge draft" })).toBeVisible(); await user.keyboard("{Escape}"); - await waitFor(() => expect(screen.queryByRole("dialog", { name: "Create local Spec draft" })).not.toBeInTheDocument()); + await waitFor(() => expect(screen.queryByRole("dialog", { name: "Create local knowledge draft" })).not.toBeInTheDocument()); expect(trigger).toHaveFocus(); }); @@ -845,10 +845,10 @@ describe("Inbox Spec-authoring workbench", () => { await openDrafts(user); await user.click(await screen.findByRole("button", { name: "Create manually" })); - const dialog = await screen.findByRole("dialog", { name: "Create local Spec draft" }); + const dialog = await screen.findByRole("dialog", { name: "Create local knowledge draft" }); const title = within(dialog).getByRole("textbox", { name: "Title" }); fireEvent.change(title, { target: { value: "Original reviewed title" } }); - fireEvent.change(within(dialog).getByRole("textbox", { name: "Spec body" }), { target: { value: "Original body." } }); + fireEvent.change(within(dialog).getByRole("textbox", { name: "Knowledge body" }), { target: { value: "Original body." } }); fireEvent.change(within(dialog).getByRole("textbox", { name: "Rationale" }), { target: { value: "Original rationale." } }); await user.click(within(dialog).getByRole("button", { name: "Save draft" })); await waitFor(() => expect(staleRequest).toBeDefined()); @@ -1092,8 +1092,8 @@ describe("Inbox Spec-authoring workbench", () => { await screen.findByRole("heading", { level: 2, name: draft.title }); await user.click(screen.getByRole("button", { name: "Publish for review" })); const confirmation = await screen.findByRole("alertdialog", { name: "Publish this draft for review?" }); - expect(within(confirmation).getByText(/Git-tracked proposal for teammate review/)).toBeVisible(); - expect(within(confirmation).getByText(/does not change the Spec or share anything automatically/)).toBeVisible(); + expect(within(confirmation).getByText(/pending Markdown proposal in this checkout/)).toBeVisible(); + expect(within(confirmation).getByText(/Project knowledge changes only after approval/)).toBeVisible(); expect(within(confirmation).getByText("Git step still required")).toBeVisible(); expect(preview).not.toHaveBeenCalled(); expect(apply).not.toHaveBeenCalled(); diff --git a/packages/hub-web/src/app/navigation.ts b/packages/hub-web/src/app/navigation.ts index 0c2ee478..5fa1f9bd 100644 --- a/packages/hub-web/src/app/navigation.ts +++ b/packages/hub-web/src/app/navigation.ts @@ -4,6 +4,7 @@ import { GitPullRequestArrow, HeartPulse, House, + Inbox, Network, Search, Send, @@ -14,7 +15,7 @@ import type { CapabilityName } from "../api/types"; export type NavigationGroupId = "project-memory" | "teamwork" | "system"; export type NavigationPlacement = "launcher" | "primary" | "footer"; -export type NavigationCountSource = "relays" | "active-jobs"; +export type NavigationCountSource = "inbox" | "relays" | "active-jobs"; export type NavigationAvailability = | { kind: "always" } @@ -40,7 +41,7 @@ export interface NavigationGroup { } export const navigationGroups: readonly NavigationGroup[] = [ - { id: "project-memory", label: "Project Memory", placement: "primary", defaultExpanded: true }, + { id: "project-memory", label: "Project", placement: "primary", defaultExpanded: true }, { id: "teamwork", label: "Teamwork", placement: "primary", defaultExpanded: true }, { id: "system", label: "System", placement: "footer", defaultExpanded: false, countSource: "active-jobs" }, ]; @@ -80,6 +81,16 @@ export const navigationItems: readonly NavigationItem[] = [ placement: "primary", availability: { kind: "runtime", capability: "graph" }, }, + { + id: "inbox", + label: "Inbox", + path: "/inbox", + icon: Inbox, + group: "project-memory", + placement: "primary", + availability: { kind: "runtime", capability: "inbox" }, + countSource: "inbox", + }, { id: "relays", label: "Relays", @@ -104,7 +115,8 @@ export const navigationItems: readonly NavigationItem[] = [ label: "Team", path: "/members", icon: UsersRound, - placement: "footer", + group: "teamwork", + placement: "primary", availability: { kind: "runtime", capability: "members" }, }, { diff --git a/packages/hub-web/src/dev/fixture-api.ts b/packages/hub-web/src/dev/fixture-api.ts index c267d46c..b95763ba 100644 --- a/packages/hub-web/src/dev/fixture-api.ts +++ b/packages/hub-web/src/dev/fixture-api.ts @@ -1,3 +1,4 @@ +import { isInboxCreate, isInboxUpdate } from "../lib/inbox-change"; import type { FixtureApiOptions, HubApi, JobSubscription } from "../api/client"; import type { ActivityItem, @@ -2870,6 +2871,15 @@ class FixtureHubApi implements HubApi { : "Remove the checkout-local Inbox draft.", }] : []; + const changedKnowledge = proposal?.change; + const knowledgePath = changedKnowledge?.kind === "knowledge.create" + ? changedKnowledge.entityKind === "pattern" + ? `.mex/patterns/${fixtureInboxCreatedSpecId}.md` + : `.mex/context/${changedKnowledge.entityKind}-${fixtureInboxCreatedSpecId}.md` + : changedKnowledge?.kind === "knowledge.update" + ? wikiEntities.find((entity) => entity.id === changedKnowledge.target.id)?.location.path + ?? `.mex/context/${changedKnowledge.target.kind}-${changedKnowledge.target.id}.md` + : undefined; const primaryChanges: InboxOperationPreviewResponse["preview"]["changes"] = action.kind === "inbox.draft.save" || action.kind === "inbox.draft.delete" ? [] : action.kind === "inbox.publish" @@ -2882,16 +2892,16 @@ class FixtureHubApi implements HubApi { }] : action.kind === "inbox.approve" ? [ - ...(proposal?.change.kind === "spec.create" ? [{ + ...(isInboxCreate(proposal?.change) ? [{ kind: "create" as const, - path: `.mex/specs/${fixtureInboxCreatedSpecId}.md`, - diff: `--- /dev/null\n+++ b/.mex/specs/${fixtureInboxCreatedSpecId}.md\n+title: ${proposal.title}\n`, + path: knowledgePath ?? `.mex/specs/${fixtureInboxCreatedSpecId}.md`, + diff: `--- /dev/null\n+++ b/${knowledgePath ?? `.mex/specs/${fixtureInboxCreatedSpecId}.md`}\n+title: ${proposal!.title}\n`, beforeRevision: null, afterRevision: revision("8"), }] : [{ kind: "update" as const, - path: `.mex/specs/${fixtureInboxSpecId}.md`, - diff: `--- a/.mex/specs/${fixtureInboxSpecId}.md\n+++ b/.mex/specs/${fixtureInboxSpecId}.md\n+The release gate records exact reviewed evidence.\n`, + path: knowledgePath ?? `.mex/specs/${fixtureInboxSpecId}.md`, + diff: `--- a/${knowledgePath ?? `.mex/specs/${fixtureInboxSpecId}.md`}\n+++ b/${knowledgePath ?? `.mex/specs/${fixtureInboxSpecId}.md`}\n+The release gate records exact reviewed evidence.\n`, beforeRevision: revision("3"), afterRevision: revision("8"), }]), { @@ -2935,7 +2945,7 @@ class FixtureHubApi implements HubApi { : action.kind === "inbox.publish" ? [{ purpose: "activity", id: eventId }, { purpose: "proposal", id: publishedProposalId }] : action.kind === "inbox.approve" - ? proposal?.change.kind === "spec.create" + ? isInboxCreate(proposal?.change) ? [{ purpose: "activity", id: eventId }, { purpose: "spec-entity", id: fixtureInboxCreatedSpecId }] : [{ purpose: "activity", id: eventId }] : [{ purpose: "activity", id: eventId }]; @@ -2982,7 +2992,7 @@ class FixtureHubApi implements HubApi { if (action.kind === "inbox.draft.save") { const id = action.draftId ?? envelope.receipt.purposeIds.find((item) => item.purpose === "inbox-draft")?.id; if (id !== undefined) { - const descriptor = action.draft.change.kind === "spec.create" + const descriptor = isInboxCreate(action.draft.change) ? { entityKind: action.draft.change.entityKind, title: action.draft.change.title } : { entityKind: action.draft.change.target.kind, title: action.draft.change.target.title ?? action.draft.change.target.id }; const next: InboxDraftDetail = { @@ -3035,7 +3045,7 @@ class FixtureHubApi implements HubApi { ))?.afterRevision ?? revision("9"); let updated: InboxProposalDetail; if (action.kind === "inbox.repair") { - const descriptor = action.replacement.change.kind === "spec.create" + const descriptor = isInboxCreate(action.replacement.change) ? { entityKind: action.replacement.change.entityKind, title: action.replacement.change.title, @@ -3097,7 +3107,7 @@ class FixtureHubApi implements HubApi { : [{ kind: "entity" as const, entity: { id: proposalId, kind: "proposal" } }]; const approvalTarget = action.kind !== "inbox.approve" ? [] - : proposals[0]?.change.kind === "spec.create" + : isInboxCreate(proposals[0]?.change) ? [{ kind: "entity" as const, entity: { @@ -3106,7 +3116,7 @@ class FixtureHubApi implements HubApi { kind: proposals[0].change.entityKind, }, }] - : proposals[0]?.change.kind === "spec.update" + : isInboxUpdate(proposals[0]?.change) ? [{ kind: "entity" as const, entity: structuredClone(proposals[0].change.target) }] : []; if (actionName !== null) { diff --git a/packages/hub-web/src/lib/inbox-change.ts b/packages/hub-web/src/lib/inbox-change.ts new file mode 100644 index 00000000..80340a48 --- /dev/null +++ b/packages/hub-web/src/lib/inbox-change.ts @@ -0,0 +1,20 @@ +import type { InboxDraftInput, InboxKnowledgeKind } from "../api/types"; + +export const inboxKnowledgeKinds: readonly InboxKnowledgeKind[] = [ + "architecture", "component", "convention", "decision", "pattern", "guide", +]; + +export type InboxCreateChange = Extract; +export type InboxUpdateChange = Extract; + +export function isInboxCreate(change: InboxDraftInput["change"] | undefined): change is InboxCreateChange { + return change?.kind === "spec.create" || change?.kind === "knowledge.create"; +} + +export function isInboxUpdate(change: InboxDraftInput["change"] | undefined): change is InboxUpdateChange { + return change?.kind === "spec.update" || change?.kind === "knowledge.update"; +} + +export function isInboxKnowledgeKind(kind: string): kind is InboxKnowledgeKind { + return inboxKnowledgeKinds.some((candidate) => candidate === kind); +} diff --git a/packages/hub-web/src/pages/InboxMutationDialogs.tsx b/packages/hub-web/src/pages/InboxMutationDialogs.tsx index 9caa0121..77ac60d7 100644 --- a/packages/hub-web/src/pages/InboxMutationDialogs.tsx +++ b/packages/hub-web/src/pages/InboxMutationDialogs.tsx @@ -1,4 +1,4 @@ -import { useMutation } from "@tanstack/react-query"; +import { useInfiniteQuery, useMutation } from "@tanstack/react-query"; import { AlertTriangle, CheckCircle2, @@ -29,6 +29,8 @@ import type { InboxOperationPreviewResponse, InboxProposalDetail, InboxSpecKind, + InboxEntityKind, + InboxKnowledgeKind, TeamActorRef, } from "../api/types"; import { @@ -64,6 +66,8 @@ import { NativeSelect, NativeSelectOption } from "../components/primitives/nativ import { Textarea } from "../components/primitives/textarea"; import { ErrorState, StatePanel, StatusPill, formatDate, sentenceCase } from "../components/ui"; import styles from "../styles/inbox-mutations.module.css"; +import { boundedNextCursor, MAX_WORKBENCH_PAGES } from "../lib/bounds"; +import { inboxKnowledgeKinds, isInboxCreate, isInboxUpdate, isInboxKnowledgeKind } from "../lib/inbox-change"; type CreateChange = Extract; type CreateRelation = NonNullable; @@ -166,10 +170,10 @@ function actorLabel(actor: TeamActorRef): string { function changeLabel( changeKind: InboxDraftDetail["changeKind"], - entityKind: InboxSpecKind, + entityKind: InboxEntityKind, ): string { const label = entityKind === "spec" ? "Spec" : entityKind.replaceAll("_", " "); - return `${changeKind === "spec.create" ? "New" : "Update"} ${label}`; + return `${changeKind.endsWith(".create") ? "New" : "Update"} ${label}`; } function hasLoneSurrogate(value: string): boolean { @@ -349,6 +353,44 @@ function ExactPreviewDetails({ envelope }: { envelope: InboxOperationPreviewResp ); } +function KnowledgeTargetPicker({ kind, targetId, targetTitle, busy, onSelect }: { + kind: InboxKnowledgeKind; + targetId: string; + targetTitle: string; + busy: boolean; + onSelect(id: string): void; +}) { + const api = useHubApi(); + const records = useInfiniteQuery({ + queryKey: ["inbox", "knowledge-targets", kind], + queryFn: ({ pageParam }) => api.listWikiEntities({ kind, limit: 25, ...(pageParam ? { cursor: pageParam } : {}) }), + initialPageParam: undefined as string | undefined, + getNextPageParam: (page, pages) => boundedNextCursor(page.nextCursor, pages.length), + retry: false, + }); + const rows = records.data?.pages.flatMap((page) => page.items) ?? []; + return ( + + Knowledge to update + onSelect(event.currentTarget.value)}> + {records.isPending ? "Loading knowledge…" : "Choose a record"} + {targetId && !rows.some((row) => row.id === targetId) + ? {targetTitle || targetId} : null} + {rows.map((row) => {row.title})} + + {records.isError ? Knowledge could not be loaded. : null} + {records.hasNextPage ? : null} + {(records.data?.pages.length ?? 0) >= MAX_WORKBENCH_PAGES && records.data?.pages.at(-1)?.nextCursor + ? This picker reached its page limit. Open Context to find the record. : null} + {targetId ? + Open current record + {" · "} + : Select a record to load its current wording.} + + ); +} + function DraftEditorDialog({ draft, repair, @@ -380,6 +422,8 @@ function DraftEditorDialog({ targetRevisions: repair.targetRevisions, }); const existingChange = sourceInput?.change; + const legacy = existingChange?.kind.startsWith("spec.") ?? false; + const subject = legacy ? "Spec" : "knowledge"; const existingExpectations = new Map( (sourceInput?.targetRevisions ?? []).map((item) => [item.target.id, item]), ); @@ -390,46 +434,46 @@ function DraftEditorDialog({ ? undefined : existingExpectations.get(existingRelation.target.id); const [mode, setMode] = useState<"create" | "update">( - existingChange?.kind === "spec.update" ? "update" : "create", + isInboxUpdate(existingChange) ? "update" : "create", ); const [includeTitle, setIncludeTitle] = useState( - existingChange?.kind === "spec.update" + isInboxUpdate(existingChange) ? Object.hasOwn(existingChange.patch, "title") : false, ); const [includeSummary, setIncludeSummary] = useState( - existingChange?.kind === "spec.update" + isInboxUpdate(existingChange) ? Object.hasOwn(existingChange.patch, "summary") : false, ); const [includeBody, setIncludeBody] = useState( - existingChange?.kind === "spec.update" + isInboxUpdate(existingChange) ? Object.hasOwn(existingChange.patch, "body") : true, ); - const [entityKind, setEntityKind] = useState( - existingChange?.kind === "spec.create" ? existingChange.entityKind : "requirement", + const [entityKind, setEntityKind] = useState( + isInboxCreate(existingChange) ? existingChange.entityKind : "pattern", ); const [title, setTitle] = useState( - existingChange?.kind === "spec.create" + isInboxCreate(existingChange) ? existingChange.title : existingChange?.patch.title ?? "", ); const [summary, setSummary] = useState( - existingChange?.kind === "spec.create" + isInboxCreate(existingChange) ? existingChange.summary ?? "" : existingChange?.patch.summary ?? "", ); const [body, setBody] = useState( - existingChange?.kind === "spec.create" + isInboxCreate(existingChange) ? existingChange.body : existingChange?.patch.body ?? "", ); const [status, setStatus] = useState<"in_flight" | "promoted">( - existingChange?.kind === "spec.create" ? existingChange.status : "in_flight", + isInboxCreate(existingChange) ? existingChange.status : "in_flight", ); const [topicsText, setTopicsText] = useState( - existingChange?.kind === "spec.create" + isInboxCreate(existingChange) ? (existingChange.topics ?? []).map((id) => { const expectation = existingExpectations.get(id); return expectation === undefined @@ -451,15 +495,15 @@ function DraftEditorDialog({ existingRelationExpectation ? String(existingRelationExpectation.semanticRevision) : "", ); const [targetId, setTargetId] = useState( - existingChange?.kind === "spec.update" ? existingChange.target.id : "", + isInboxUpdate(existingChange) ? existingChange.target.id : "", ); - const [targetKind, setTargetKind] = useState( - existingChange?.kind === "spec.update" ? existingChange.target.kind : "spec", + const [targetKind, setTargetKind] = useState( + isInboxUpdate(existingChange) ? existingChange.target.kind : "pattern", ); const [targetTitle, setTargetTitle] = useState( - existingChange?.kind === "spec.update" ? existingChange.target.title ?? "" : "", + isInboxUpdate(existingChange) ? existingChange.target.title ?? "" : "", ); - const existingTarget = existingChange?.kind === "spec.update" + const existingTarget = isInboxUpdate(existingChange) ? existingExpectations.get(existingChange.target.id) : undefined; const [targetRevision, setTargetRevision] = useState(existingTarget?.revision ?? ""); @@ -469,11 +513,37 @@ function DraftEditorDialog({ const [rationale, setRationale] = useState(sourceInput?.rationale ?? ""); const preservedEvidence = sourceInput?.evidence ?? []; const [evidenceNote, setEvidenceNote] = useState(""); + const [targetNotice, setTargetNotice] = useState(""); const [envelope, setEnvelope] = useState(null); const [confirmOpen, setConfirmOpen] = useState(false); const confirmTriggerRef = useRef(null); const applySucceeded = useRef(false); const previewGeneration = useRef(0); + const targetGeneration = useRef(0); + const targetLookup = useMutation({ + mutationFn: ({ id }: { id: string; generation: number }) => api.getWikiEntity(id), + onSuccess: (detail, { id, generation }) => { + if (generation !== targetGeneration.current) return; + if (detail.entity.id !== id || !isInboxKnowledgeKind(detail.entity.kind) || detail.entity.version.semanticRevision < 1) { + setTargetNotice("This record is not available for a knowledge proposal."); + return; + } + setTargetId(id); + setTargetKind(detail.entity.kind); + setTargetTitle(detail.entity.title); + setTargetRevision(detail.entity.version.contentHash); + setSemanticRevision(String(detail.entity.version.semanticRevision)); + const bodyFits = !detail.body.truncated && canonicalText(detail.body.content, 16 * 1024, true); + if (!sourceInput) { + setTitle(detail.entity.title); + setSummary(detail.entity.summary ?? ""); + setBody(bodyFits ? detail.body.content : ""); + setIncludeBody(bodyFits); + } + setTargetNotice(bodyFits ? "Current record loaded. Only the selected fields will change." : "This body exceeds the editor limit. You can update its title or summary, or write a complete replacement body."); + invalidate(); + }, + }); const preview = useMutation({ mutationFn: ({ request }: { request: InboxOperationPreviewRequest; generation: number }) => ( api.previewInboxOperation(request) @@ -538,22 +608,33 @@ function DraftEditorDialog({ setter(value); invalidate(); }; + const selectKnowledgeTarget = (id: string) => { + targetGeneration.current += 1; + setTargetRevision(""); + setTargetNotice(""); + invalidate(); + if (!id) { + setTargetId(""); setTargetTitle(""); targetLookup.reset(); + return; + } + targetLookup.mutate({ id, generation: targetGeneration.current }); + }; const targetRevisionValid = /^[a-f0-9]{64}$/.test(targetRevision); const semanticRevisionNumber = Number(semanticRevision); const topicAttestations = parseTopicAttestations(topicsText); const relationSemanticRevisionNumber = Number(relationSemanticRevision); - const relationIsValid = relationType === "none" || ( + const relationIsValid = !legacy || relationType === "none" || ( /^mx_[0-7][0-9A-HJKMNP-TV-Z]{25}$/.test(relationTargetId) && /^[a-f0-9]{64}$/.test(relationRevision) && Number.isInteger(relationSemanticRevisionNumber) && relationSemanticRevisionNumber > 0 && canonicalText(relationTargetTitle, 512, false) - && relationAccepted(entityKind, relationType, relationTargetKind) + && legacy && relationAccepted(entityKind as InboxSpecKind, relationType, relationTargetKind) ); const createExpectationById = new Map(); let createExpectationConflict = false; for (const item of topicAttestations.items) createExpectationById.set(item.id, item); - if (relationType !== "none" && relationIsValid) { + if (legacy && relationType !== "none" && relationIsValid) { const current = createExpectationById.get(relationTargetId); if (current !== undefined && ( current.revision !== relationRevision @@ -576,7 +657,7 @@ function DraftEditorDialog({ semanticRevision: item.semanticRevision, })); const updateHasPatch = includeTitle || includeSummary || includeBody; - const canPreview = canonicalText(rationale, 8 * 1024, true) + const canPreview = !targetLookup.isPending && canonicalText(rationale, 8 * 1024, true) && (mode === "create" ? canonicalText(body, 16 * 1024, true) && canonicalText(title, 512, true) : (!includeBody || canonicalText(body, 16 * 1024, true)) @@ -596,53 +677,35 @@ function DraftEditorDialog({ && updateHasPatch )); - const draftInput = (): InboxDraftInput => ({ - change: mode === "create" - ? { - kind: "spec.create", - entityKind, - title, - body, - ...(summary === "" ? {} : { summary }), - status, - ...(topicAttestations.items.length === 0 - ? {} - : { topics: topicAttestations.items.map((item) => item.id) }), - ...(relationType === "none" - ? {} - : { - relation: buildCreateRelation( - relationType, - relationTargetId, - relationTargetKind, - relationTargetTitle, - )!, - }), - } - : { - kind: "spec.update", - target: { - id: targetId, - kind: targetKind, - ...(targetTitle === "" ? {} : { title: targetTitle }), - }, - patch: { - ...(includeTitle ? { title } : {}), - ...(includeSummary ? { summary } : {}), - ...(includeBody ? { body } : {}), - }, - }, - rationale, - evidence: [ - ...preservedEvidence, - ...(evidenceNote === "" ? [] : [{ kind: "manual" as const, note: evidenceNote }]), - ], - targetRevisions: mode === "create" ? createTargetRevisions : [{ - target: { kind: "entity", id: targetId }, - revision: targetRevision, - semanticRevision: semanticRevisionNumber, - }], - }); + const draftInput = (): InboxDraftInput => { + const createFields = { + title, body, ...(summary === "" ? {} : { summary }), status, + ...(topicAttestations.items.length === 0 ? {} : { topics: topicAttestations.items.map((item) => item.id) }), + }; + const patch = { + ...(includeTitle ? { title } : {}), + ...(includeSummary ? { summary } : {}), + ...(includeBody ? { body } : {}), + }; + const target = { id: targetId, ...(targetTitle === "" ? {} : { title: targetTitle }) }; + return { + change: mode === "create" + ? legacy + ? { kind: "spec.create", entityKind: entityKind as InboxSpecKind, ...createFields, + ...(relationType === "none" ? {} : { + relation: buildCreateRelation(relationType, relationTargetId, relationTargetKind, relationTargetTitle)!, + }) } + : { kind: "knowledge.create", entityKind: entityKind as InboxKnowledgeKind, ...createFields } + : legacy + ? { kind: "spec.update", target: { ...target, kind: targetKind as InboxSpecKind }, patch } + : { kind: "knowledge.update", target: { ...target, kind: targetKind as InboxKnowledgeKind }, patch }, + rationale, + evidence: [...preservedEvidence, ...(evidenceNote === "" ? [] : [{ kind: "manual" as const, note: evidenceNote }])], + targetRevisions: mode === "create" ? createTargetRevisions : [{ + target: { kind: "entity", id: targetId }, revision: targetRevision, semanticRevision: semanticRevisionNumber, + }], + }; + }; const request = (): InboxOperationPreviewRequest => repair === null ? { @@ -666,7 +729,7 @@ function DraftEditorDialog({ const editorTitle = isRepair ? "Repair proposal manually" - : draft === null ? "Create local Spec draft" : "Edit local Spec draft"; + : draft === null ? "Create local knowledge draft" : `Edit local ${subject} draft`; const previewLabel = isRepair ? "Review repaired proposal" : "Preview local draft"; const wordingInitialFocusRef = mode === "create" || includeTitle ? titleRef @@ -690,8 +753,8 @@ function DraftEditorDialog({ {editorTitle} {isRepair - ? "Update the proposal marked Needs refresh against current Spec content. Repair returns it to teammate review without writing the Spec." - : "This draft stays private to this checkout. Saving it does not publish a proposal or change the Spec."} + ? `Update this proposal against current ${subject} content. Repair returns it to teammate review without changing project knowledge.` + : "This draft stays private to this checkout. Saving does not publish a proposal or change project knowledge."}
    @@ -703,38 +766,53 @@ function DraftEditorDialog({ className={styles.select} disabled={draft !== null || isRepair} id="draft-change-kind" - onChange={(event) => change(setMode, event.currentTarget.value as "create" | "update")} + onChange={(event) => { + targetGeneration.current += 1; + targetLookup.reset(); + change(setMode, event.currentTarget.value as "create" | "update"); + }} ref={changeTypeRef} value={mode} > - Create a Spec entity - Update a Spec entity + Create knowledge + Update knowledge - Spec kind + {legacy ? "Spec kind" : "Knowledge kind"} change( - mode === "create" ? setEntityKind : setTargetKind, - event.currentTarget.value as InboxSpecKind, - )} + onChange={(event) => { + change(mode === "create" ? setEntityKind : setTargetKind, event.currentTarget.value as InboxEntityKind); + if (mode === "update" && !legacy) { + targetGeneration.current += 1; + targetLookup.reset(); + setTargetId(""); setTargetTitle(""); setTargetRevision(""); setTargetNotice(""); + } + }} ref={entityKindRef} value={mode === "create" ? entityKind : targetKind} > - {specKinds.map((kind) => ( + {(legacy ? specKinds : inboxKnowledgeKinds).map((kind) => ( {sentenceCase(kind)} ))}
    + {mode === "update" && !legacy && isInboxKnowledgeKind(targetKind) ? <> + + {targetLookup.isError ? The current record could not be read. Choose it again to retry. : null} + {targetNotice ? {targetNotice} : null} + : null} {mode === "update" ? ( Included patch fields -
    +