Repository navigation
feat(knowledge): filter/overlay knowledge federation engine and submission packaging - #37
Merged
Merged
Conversation
…olution, and submission packaging
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical security, path-safety, provenance, and correctness issues remain.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a three-tier knowledge federation system with overlays, APIs, submission packaging, and LocalWiki integration.
Changes:
- Implements layered resolution, reversion, linting, and packaging.
- Adds federation and documentation API integrations.
- Adds reader controls, modals, badges, and tests.
File summaries
| File | Summary |
|---|---|
frontend-vue/src/surfaces/documentation/LocalWikiReader.vue |
Federation UI controls and interactions |
backend/tests/test_knowledge_overlay.py |
Federation integration tests |
backend/app/surfaces/documentation_api.py |
Overlay-aware document loading |
backend/app/services/knowledge_overlay.py |
Layer resolution and submission packaging |
backend/app/api/routes.py |
Federation route registration |
backend/app/api/federation_api.py |
Federation REST handlers |
Review details
Suppressed comments (6)
backend/app/api/federation_api.py:106
- The revert endpoint has the same uncaught conversion path: a malformed
layerproduces a 500 before the handler's try/except instead of a 400. Keep input parsing inside the guarded block, matching the overlay handler.
layer = int(body.get("layer", 2))
backend/app/services/knowledge_overlay.py:389
- An existing Layer 2 file that is identical to canon has
canon_existstrue but an emptydiff_from_canon; this branch then treats it as a new document and emits a full/dev/nullpatch. Distinguish a genuinely new document from a no-op overlay, and reject the latter or emit an empty patch instead of packaging the whole canon file.
diff_text = resolved["diff_from_canon"]
if not diff_text:
# New document without canon baseline; package full file diff
backend/app/services/knowledge_overlay.py:250
- This delete path also follows symlinked parents:
target.is_file()can succeed for a file outside the layer andtarget.unlink()will then delete that outside file. Validate the resolved target stays beneath the selected layer root, or use a no-follow deletion strategy, before allowing a revert.
root = self.layer_root(layer)
target = root / normalized
if target.is_file():
target.unlink()
frontend-vue/src/surfaces/documentation/LocalWikiReader.vue:235
- Deleting only the Layer 2 file does not always restore Layer 0: when a Layer 1 file exists,
revert_overlay()resolves to that community content. These new strings promise “Revert to Canon” and “restore pristine canonical baseline,” so the control misrepresents what the user will see. Rename the action to describe restoring the lower-precedence layer, or explicitly remove both upper layers.
title="Revert personal overlay and restore pristine canonical baseline"
@click="confirmRevertToCanon"
>
<UIcon name="undo" size="xs" />
<span>{{ revertingOverlay ? 'Reverting...' : 'Revert to Canon' }}</span>
frontend-vue/src/surfaces/documentation/LocalWikiReader.vue:219
- When
toggleCanonOnly()loadscanonical=true, the response replacesactiveOverlaywith a Layer 0 result whoseis_overlaidis false. This condition then removes the only toggle, so the reader cannot return to the personal/shared content without selecting the article again. Keep this control visible whileshowingCanonOnlyis true, or preserve the original overlay metadata.
v-if="activeOverlay.is_overlaid && activeOverlay.canon_exists"
type="button"
class="wiki-btn wiki-btn--xs"
:class="{ 'wiki-btn--active': showingCanonOnly }"
title="Toggle between personal overlay and canonical baseline"
@click="toggleCanonOnly"
frontend-vue/src/surfaces/documentation/LocalWikiReader.vue:448
- This icon-only close control has no accessible name (
aria-label, text, or title), so assistive technology cannot identify the button. Add a context-specific accessible label to this and the two other newly added modal close buttons.
<button type="button" class="wiki-search-clear" @click="showDiffModal = false">
<UIcon name="close" size="xs" />
</button>
- Files reviewed: 6/6 changed files
- Comments generated: 13
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+184
to
+187
| app.router.add_post("/api/knowledge/federation/overlay", handle_federation_save_overlay) | ||
| app.router.add_post("/api/knowledge/federation/revert", handle_federation_revert_overlay) | ||
| app.router.add_post("/api/knowledge/federation/preflight", handle_federation_preflight) | ||
| app.router.add_post("/api/knowledge/federation/export-submission", handle_federation_export_submission) |
| try: | ||
| from .federation_api import register_federation_routes | ||
|
|
||
| register_federation_routes(app) |
Comment on lines
+229
to
+233
| normalized = self.normalize_rel_path(rel_path) | ||
| root = self.layer_root(layer) | ||
| target = root / normalized | ||
| target.parent.mkdir(parents=True, exist_ok=True) | ||
| target.write_text(content, encoding="utf-8") |
Comment on lines
+428
to
+430
| "origin_path": resolved["effective_path"], | ||
| "canon_exists": resolved["canon_exists"], | ||
| "canon_path": resolved["canon_path"], |
Comment on lines
+432
to
+436
| "signatures": { | ||
| "local_device_fingerprint": _sha256(os.uname().nodename), | ||
| "author_id": author, | ||
| "signed_at": datetime.now(timezone.utc).isoformat(), | ||
| }, |
Comment on lines
+780
to
+785
| resolved = resolver.resolve(path, prefer_canon=prefer_canon) | ||
| if resolved.get("found"): | ||
| if prefer_canon and resolved.get("canon_exists"): | ||
| canon_path_obj = Path(resolved["canon_path"]) if resolved.get("canon_path") else None | ||
| if canon_path_obj and canon_path_obj.is_file(): | ||
| result["content"] = canon_path_obj.read_text(encoding="utf-8", errors="replace") |
| <button | ||
| type="button" | ||
| class="wiki-btn wiki-btn--xs wiki-btn--ghost" | ||
| @click="selectDocument(item.layer === 2 ? 'vault' : 'shared', item.path, item.rel_path); showFederationModal = false" |
| if (resp.ok) { | ||
| const data = await resp.json(); | ||
| activeOverlay.value = data.overlay || activeOverlay.value; | ||
| activeSource.value = "vault"; |
Comment on lines
+558
to
+560
| <div v-for="(err, i) in preflightResult.errors" :key="i" class="preflight-err-msg"> | ||
| ✗ {{ err }} | ||
| </div> |
Comment on lines
+1777
to
+1781
| .wiki-chip--canon { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| gap: 4px; | ||
| font-size: 11px; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the sovereign three-tier cascading knowledge architecture specified in KNOWLEDGE_LAYERING_AND_CONTRIBUTION_SPEC.md and AGENTS.md.
Tests