Repository navigation
Conversation
src/hyperloom_kb as AMD-BRAIN-Internal/Hyperloom-KB holds it at ad4647220 (its PR #8), unchanged: Distills, the patterns a user draws from groups of one schema's Experiences, kept as versioned entries with frozen evidence, checked against new evidence on every listing and read, carried by labels, restores, exclusions, push, and pull, and written into a directory a Curated Wiki searches; their HTTP API, RemoteClient methods, the hyperloom-kb schema, experience, and distill commands, the hyperloom-kb-distill skill, and their tests. Co-authored-by: Cursor <cursoragent@cursor.com>
…e and give distill sync a tool's directory The Experience KB code taken from Hyperloom-KB meets every limit the code-metrics gate holds a change to: - cli registers the Distill commands in two groups, authoring and upkeep, each under 80 lines; - the request handler serves push, pull, and rebind from _dispatch_sync, and GlobalSync.pull reads its page through _next_page, so neither grows past what main holds; - the record fields, Draft fields, and query values written three times or more in one module are named once; - the CLI tests take their schema from the shared Distill fixtures, and the sync tests start their three KBs in one helper, so no test repeats another's lines. add_commands takes distill_dir: distill sync writes there unless it names --dir, which stays required without one. The hyperloom-kb-distill skill names a global KB nowhere, as the hyperloom-kb skill does, and says a tool may give --dir a default. Behavior is otherwise unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
…r skill experience_kb_service runs every hyperloom-kb distill command on the workspace's service, defaulting to its schema; its distill sync writes the pages into distilled/ under the service's data home unless --dir names another directory. A push or pull line also counts the Distills it moved, unless the service still running predates them. The hyperloom-kb-distill skill installs beside hyperloom-kb, and the optimizer and setup skills point to it. The Experience KB reference gains the Distills page and their commands, routes, health counts, metrics, audit events, and data home entries, naming a global KB only by its settings as the rest of these docs do. Co-authored-by: Cursor <cursoragent@cursor.com>
Code metrics gate: PASSED with waived findings (
|
| Dimension | Limit | New | Worse | Baseline out of date | Baseline entries | vs base |
|---|---|---|---|---|---|---|
| Cyclomatic complexity | fails > 20 | 0 | 0 | 0 | 72 | +0 |
| Cognitive complexity | fails > 30 | 0 | 0 | 0 | 284 | +0 |
| Function length (lines) | fails > 80 | 0 | 0 | 0 | 449 | +0 |
| Nested block depth | fails > 5 | 0 | 0 | 0 | 27 | +0 |
| Module length (lines) | warns > 800, fails > 1200 | 1 | 0 | 0 | 53 | +0 |
| Duplicated lines per file | fails > 0 | 0 | 0 | 0 | 118 | +0 |
| Dead code (vulture) | fails > 0 | 0 | 0 | 0 | 2 | +0 |
| Check | Findings | Effect |
|---|---|---|
| Comments | 0 | |
| English only | 0 | |
| Production code imports test code | 0 | |
| Repeated literals | 0 | |
| A1 Private name of another package | 0 | |
| A8 Flag argument | 0 | |
| A9 Tuple return | 0 | |
| A10 Raw vocabulary comparison | 0 | |
| A11 Hidden global write | 0 | |
| A12 Pure forwarder | 0 | |
| A12 Single-implementation abstraction | 2 | advisory, never fails |
New violations (not in the baseline) (waived by the baseline-raise label): 1
| Unit | Dimension | Value | Limit |
|---|---|---|---|
src/hyperloom_kb/http_service.py:1 |
Module length (lines) | 1729 | fails > 1200 |
A12 Single-implementation abstraction (advisory, never fails): 2
| Where | Problem |
|---|---|
src/hyperloom_kb/distill/service.py:95 |
A12 single implementation: DistillHost is abstract and only ExperienceHTTPService (src/hyperloom_kb/http_service.py) implements it; use the implementation until a second one exists |
src/hyperloom_kb/sync.py:284 |
A12 single implementation: SyncedDistills is abstract and only DistillService (src/hyperloom_kb/distill/service.py) implements it; use the implementation until a second one exists |
How to fix
- New or worse: split the unit (extract a function, a class, a module) until it is back under the limit, or no worse than its recorded value. The baseline cannot absorb a new violation: CI refuses any baseline entry added or raised relative to the base branch.
- Baseline out of date: something improved. Run
python scripts/code_metrics.py --update-baselineand commitscripts/code_metrics_baseline.txt; the command only lowers or removes entries. - A12 Single-implementation abstraction: use the one implementation directly until a second one exists; a lower package declaring an interface for a higher one to implement is exempt.
- Override: the
baseline-raisePR label waives new, worse and baseline-growth findings and the failing design checks (they stay listed here). Use it only with the reason in the PR description; it waives nothing else. - Tools for a local run:
pip install ruff==0.16.2 complexipy==8.0.1 vulture==2.16andnpm install -g jscpd@5.4.1(or pointCODE_METRICS_JSCPDat another jscpd command, such asnpx --yes jscpd@<version>).
Module length warning: over 800 lines, within the 1200-line failure limit (not failing): 1
| Module | Lines | Limit |
|---|---|---|
src/hyperloom_kb/remote.py |
929 | warns > 800 |
Already over at the base (backlog, not this change's): 1
| Unit | Dimension | Base | Now |
|---|---|---|---|
src/hyperloom_kb/sync.py:536 GlobalSync.pull |
Function length (lines) | 86 | 82 |
93 findings in files this change does not touch
Outside this change (informational): 93
| Unit | Dimension | Baseline | Now |
|---|---|---|---|
src/hyperloom/orchestrator/enablement/recipe/projections.py project_launch_evidence |
Cognitive complexity | absent | 36 |
src/hyperloom/orchestrator/state/shared_state.py resolve_graded_comparison |
Cognitive complexity | absent | 34 |
src/hyperloom_kb/collect/mapping.py _experience |
Cognitive complexity | absent | 31 |
src/hyperloom_kb/schema.py FieldDeclaration.__post_init__ |
Cognitive complexity | absent | 32 |
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver |
Cognitive complexity | absent | 36 |
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start |
Cognitive complexity | absent | 40 |
src/kernelforge/loop/runner.py IterationLoop._collect_session_candidate |
Cognitive complexity | absent | 44 |
src/kernelforge/loop/runner.py IterationLoop._rule_on_attempt |
Cognitive complexity | absent | 38 |
src/hyperloom_kb/tests/test_global_identity_and_pull.py |
Duplicated lines per file | absent | 13 |
src/hyperloom_kb/tests/test_local_state.py |
Duplicated lines per file | absent | 13 |
src/hyperloom/inference_optimizer/cli/__init__.py _reexport_session_environment |
Function length (lines) | absent | 112 |
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_agent_lineup |
Function length (lines) | absent | 89 |
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_run_topology |
Function length (lines) | absent | 92 |
src/hyperloom/inference_optimizer/cli/__init__.py _resume_session |
Function length (lines) | absent | 171 |
src/hyperloom/inference_optimizer/cli/__init__.py _seed_fresh_session |
Function length (lines) | absent | 183 |
src/hyperloom/inference_optimizer/multi_node/cli.py _restart_multinode |
Function length (lines) | absent | 107 |
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _build_parser |
Function length (lines) | absent | 84 |
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _spawn_rank_actors |
Function length (lines) | absent | 90 |
src/kernelforge/cli/forge_loop_command.py _RunReporter.build_result |
Function length (lines) | absent | 91 |
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver |
Function length (lines) | absent | 140 |
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start |
Function length (lines) | absent | 154 |
src/kernelforge/loop/knowledge_integration.py _measure_warmstart_field |
Function length (lines) | absent | 83 |
src/kernelforge/loop/runner.py IterationLoop._close_iteration |
Function length (lines) | absent | 135 |
src/kernelforge/loop/runner.py IterationLoop._collect_session_candidate |
Function length (lines) | absent | 187 |
src/kernelforge/loop/runner.py IterationLoop._implementer_history |
Function length (lines) | absent | 112 |
...and 68 more; the job log lists every row.
Verdict computed by the gate scripts in
/home/runner/work/_temp/code-metrics-gate, not by this tree's copy.
Thresholds and sources: [tool.hyperloom.code_metrics] in pyproject.toml. Tools: complexipy 8.0.1, jscpd 5.4.1, ruff 0.16.2, vulture 2.16.
| metrics: Metrics | ||
|
|
||
| @property | ||
| def code_digest(self) -> str: ... |
| def code_digest(self) -> str: ... | ||
|
|
||
| @property | ||
| def schema_refs(self) -> tuple[str, ...]: ... |
| @property | ||
| def schema_refs(self) -> tuple[str, ...]: ... | ||
|
|
||
| def declaration_for(self, schema_ref: str) -> ExperienceDeclaration: ... |
|
|
||
| def declaration_for(self, schema_ref: str) -> ExperienceDeclaration: ... | ||
|
|
||
| def visible_experiences(self, schema_ref: str) -> tuple[Experience, ...]: ... |
|
|
||
| def visible_experiences(self, schema_ref: str) -> tuple[Experience, ...]: ... | ||
|
|
||
| def held(self, experience_id: str) -> Experience: ... |
|
|
||
| def held(self, experience_id: str) -> Experience: ... | ||
|
|
||
| def is_visible(self, experience: Experience) -> bool: ... |
|
|
||
| def is_visible(self, experience: Experience) -> bool: ... | ||
|
|
||
| def missing_files(self, refs: Iterable[FileRef]) -> tuple[str, ...]: ... |
|
|
||
| def missing_files(self, refs: Iterable[FileRef]) -> tuple[str, ...]: ... | ||
|
|
||
| def file_path(self, ref: FileRef) -> Path: ... |
|
|
||
| def file_path(self, ref: FileRef) -> Path: ... | ||
|
|
||
| def kb_state(self, schema_ref: str) -> str: ... |
|
|
||
| def kb_state(self, schema_ref: str) -> str: ... | ||
|
|
||
| def lock_schema(self, connection: Connection, schema_ref: str) -> None: ... |
| metrics: Metrics | ||
|
|
||
| @property | ||
| def code_digest(self) -> str: ... |
| def code_digest(self) -> str: ... | ||
|
|
||
| @property | ||
| def schema_refs(self) -> tuple[str, ...]: ... |
| @property | ||
| def schema_refs(self) -> tuple[str, ...]: ... | ||
|
|
||
| def declaration_for(self, schema_ref: str) -> ExperienceDeclaration: ... |
|
|
||
| def declaration_for(self, schema_ref: str) -> ExperienceDeclaration: ... | ||
|
|
||
| def visible_experiences(self, schema_ref: str) -> tuple[Experience, ...]: ... |
|
|
||
| def visible_experiences(self, schema_ref: str) -> tuple[Experience, ...]: ... | ||
|
|
||
| def held(self, experience_id: str) -> Experience: ... |
|
|
||
| def held(self, experience_id: str) -> Experience: ... | ||
|
|
||
| def is_visible(self, experience: Experience) -> bool: ... |
|
|
||
| def is_visible(self, experience: Experience) -> bool: ... | ||
|
|
||
| def missing_files(self, refs: Iterable[FileRef]) -> tuple[str, ...]: ... |
|
|
||
| def missing_files(self, refs: Iterable[FileRef]) -> tuple[str, ...]: ... | ||
|
|
||
| def file_path(self, ref: FileRef) -> Path: ... |
|
|
||
| def file_path(self, ref: FileRef) -> Path: ... | ||
|
|
||
| def kb_state(self, schema_ref: str) -> str: ... |
|
|
||
| def kb_state(self, schema_ref: str) -> str: ... | ||
|
|
||
| def lock_schema(self, connection: Connection, schema_ref: str) -> None: ... |
This branch has not been deployed
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.
Description: what and why
Adds Distills to the Experience KB. A Distill is a pattern a user draws from a group of one schema's Experiences: a scope that selects the group, a claim written in a registered form, and the evidence, which is the group's members, each classified as supporting, contradicting, or irrelevant to the claim.
distill syncwrites every visible Distill as a markdown page into a directory a Curated Wiki searches. Neither wiki enters a prompt.The PR has three commits:
src/hyperloom_kbexactly as AMD-BRAIN-Internal/Hyperloom-KB holds it atad4647220. That is its PR Update README.md #8, already reviewed and merged there, and this commit matches it file for file.The changes the code-metrics gate needs, which Hyperloom-KB does not run:
_dispatch_sync;GlobalSync.pullreads its page through_next_page;add_commands(..., distill_dir=...)givesdistill synca tool's default directory;These go back to Hyperloom-KB in a follow-up PR, so the two trees stay identical.
The Hyperloom integration:
distill syncdefaults todistilled/under the service's data home);hyperloom-kb-distillskill installed besidehyperloom-kb;docs/reference/experience-kb-distill.mdand the Experience KB reference, which name a global KB only by its settings, as these docs already do.Linked issue(s): none. The source is AMD-BRAIN-Internal/Hyperloom-KB PR Update README.md #8.
Tests: added and updated.
src/hyperloom_kb/tests/test_distill_store.py,test_distill_api.py,test_distill_sync.py, andtest_distill_cli.py.test_cli.py(embedding,distill_dir, the skills naming every command),test_http_service.py(the/healthshape), andtest_experience_kb_service.py(the workspace sync directory, the push and pull line, the skill pointers).pytest src/hyperloom_kb/tests src/hyperloom/inference_optimizer/tests/test_experience_kb_service.py src/hyperloom/inference_optimizer/tests/test_packaging_lint.py: 347 passed, 1 skipped.ruff checkandruff format --check: clean.diff-coveragainstorigin/main: 96% of the changed production lines are covered.Size/complexity triggers crossed: split, or why the shape is right:
size-exception: 3487 production Python lines. Commit 1 is code already reviewed and merged in Hyperloom-KB, and splitting it here would only replay that review in pieces. Commits 2 and 3 are the parts new to this repository, and each reviews on its own.baseline-raise:src/hyperloom_kb/http_service.pygoes from 1539 to 1729 lines (limit 1200). The Distill host methods and routes join the service's single request handler. Splittinghttp_service.pywould move existing code unrelated to this feature, so it belongs in a change of its own.GlobalSync.pullgoes from 86 to 82 lines, andRequestHandler._dispatchfrom 91 to under 80.DistillHostandSyncedDistillsare Protocols, each with one implementation. Each is declared by the lower module, the Distill package and sync, for the higher one, the HTTP service, to implement, which is the exemption that rule names.If this simplifies or refactors: commit 2 moves code without changing any contract.
_dispatchinto_dispatch_sync, keeping their bodies and refusals.GlobalSync.pullreads its page through_next_page, which keeps the restart-from-the-start rule and the push reset after a lost cursor.Observable effect: what an operator will now see.
hyperloom-kb(andpython -m hyperloom.inference_optimizer.experience_kb_service) gainsschema show,experience get, anddistill explore | forms | add-form | preview | create | update | get | draft | list | changes | delete | restore-entry | sync. A preview the KB would refuse exits 1, as does a draft file that cannot be read. In a workspace,distill syncwrites todistilled/under the service's data home unless--dirnames another directory.GET /v1/schemas/{schema_ref},GET /v1/experiences/{id}, and/v1/distill/....GET /healthgainsdistills: per schema, the visible and deleted Distills, how many needed attention at the last check, and when that check ran. Health never recomputes evidence, so it is as cheap as before.distillscounts, and the workspace push and pull line shows them, unless the service still running predates Distills.hyperloom_kb_distill_entries,hyperloom_kb_distill_writes_total,hyperloom_kb_distill_evidence_seconds,hyperloom_kb_distill_changes, andhyperloom_kb_distill_checked_timestamp_seconds.auditactionsregister_distill_form,distill_create,distill_update, anddistill_receive. Thewritestable records arecord_kind.hyperloom-kb-distillinstalls under.agents,.claude, and.cursorbesidehyperloom-kb.Breaking changes: yes, for rollback only. On start, a service migrates its database to schema version 2. The migration only adds tables and a column, but code from before this PR refuses a version 2 database, so rolling a workspace back to an older Hyperloom means restoring
database.sqlite3from before the upgrade. A global KB that predates Distills keeps syncing every Experience: a push counts the Distills it holds back underheld_backand sends them once that KB is upgraded.PR addresses single concern: yes, Distills. The three commits are the reviewed code, the changes this repository's gate needs, and the Hyperloom integration.
Root cause is upstream: not applicable.