Skip to content

feat(init): add --template with a gittensor seed pack - #133

Merged
plind-junior merged 1 commit into
vouchdev:testfrom
dripsmvcp:fix/132-gittensor-template
May 29, 2026
Merged

feat(init): add --template with a gittensor seed pack#133
plind-junior merged 1 commit into
vouchdev:testfrom
dripsmvcp:fix/132-gittensor-template

Conversation

@dripsmvcp

@dripsmvcp dripsmvcp commented May 28, 2026

Copy link
Copy Markdown
Contributor

Adds a named-template system to vouch init so a fresh KB can be seeded for a specific adoption. vouch init --template gittensor seeds cited, approved starter claims about Gittensor SN74 OSS-mining scoring (merged-PR base reward, GitHub-identity verification, code-quality factors, repo allow-list policy, issue-solving multipliers, sybil thresholds, emission split) so teams can adopt vouch as their review-gated decision memory.

Templates are a registry in onboarding.py that compose the existing put_source / put_claim primitives — no new method surface, on-disk layout, or object-model change (so no VEP needed). Seeding is idempotent: content-addressed sources and id-keyed claims are never duplicated on re-init. default keeps the prior single-claim starter; seed_starter_kb is retained as a thin wrapper for back-compat.

The seeded gittensor claims are deliberately starter-grade (confidence <= 0.8) and the seed source documents that values should be re-verified and superseded against the live spec via vouch supersede.

Refs #132

What changed

Why

What might break

VEP

Tests

  • make check passes locally (lint + mypy + pytest)
  • New / changed behaviour has a test
  • CHANGELOG.md updated under ## [Unreleased]

Summary by CodeRabbit

Release Notes

  • New Features
    • The vouch init command now supports template selection via a --template option
    • Introduces a new gittensor template alongside the default template
    • Seeding output displays claim and source counts for the selected template
    • Post-initialization guidance adapts based on template selection
    • Template choice is recorded in audit logs

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b27ce65-2fd5-4569-b32e-961ea445c558

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR introduces a template-based onboarding system for vouch init. Users can now select from named, reusable templates (default and gittensor) via --template. Each template defines sources and claims seeded idempotently into the KB. The CLI imports and wires the new template API, and tests validate template selection, idempotent behavior, and integration with the search and doctor commands.

Changes

Template-based onboarding initialization

Layer / File(s) Summary
Template specification and definitions
src/vouch/onboarding.py
Introduces Template dataclass with sources and claims fields, defines frozen SourceSpec and ClaimSpec structures, adds GITTENSOR_SOURCE_TEXT constant, and composes _DEFAULT_TEMPLATE and _GITTENSOR_TEMPLATE with their respective sources and claims.
Template seeding API and registry
src/vouch/onboarding.py
Implements seed_template() for idempotent content-addressed source creation and stable claim lookup, exports TEMPLATES registry, available_templates() function, and SeedResult dataclass. Refactors seed_starter_kb() as a wrapper over seed_template() with the default template and updates __all__ exports.
CLI template selection and seeding
src/vouch/cli.py
Updates vouch init command to import template functions, adds --template Click option, replaces seed_starter_kb() with seed_template(), extends audit logging with selected template, and varies output messaging and "Next steps" guidance by template selection.
Test coverage for template API and CLI integration
tests/test_onboarding.py
Adds unit tests for available_templates(), seed_template() error handling, gittensor seeding assertions, and idempotency verification. Updates CLI init tests to assert template selection, adds init --template gittensor integration test validating searchable merged claims and successful doctor run, and adjusts idempotency assertion to generic "already present" substring.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • vouchdev/vouch#55: Prior PR that introduced vouch init onboarding seeding; this PR refactors that starter approach into a reusable template system while maintaining backward compatibility.

Poem

🐰 Behold, the template garden grows—
Default and gittensor now compose
Seeds planted idempotent and true,
Init picks templates, old and new!
Vouch knows the way, no starter chains,
Just reusable knowledge—onboarding reigns! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(init): add --template with a gittensor seed pack' accurately describes the main change: adding a --template option to the init command with a new gittensor template for seeding knowledge bases.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/vouch/onboarding.py (1)

353-362: ⚡ Quick win

Avoid coupling seed_starter_kb() to the default template's source order.

Line 359 assumes the starter source is always the first seeded source. If default ever gains another source, this wrapper can return the wrong source_id. Derive it from STARTER_SOURCE_TEXT (or the "starter" source spec) instead of indexing result.source_ids.

♻️ Proposed fix
 def seed_starter_kb(
     store: KBStore, *, approved_by: str = "vouch-init"
 ) -> StarterSeedResult:
     """Seed the default starter claim. Thin wrapper over `seed_template`."""
     result = seed_template(store, template="default", approved_by=approved_by)
+    starter_source_id = sha256_hex(STARTER_SOURCE_TEXT.encode("utf-8"))
     return StarterSeedResult(
-        source_id=result.source_ids[0],
+        source_id=starter_source_id,
         claim_id=STARTER_CLAIM_ID,
         created_source=result.created_sources > 0,
         created_claim=result.created_claims > 0,
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/vouch/onboarding.py` around lines 353 - 362, seed_starter_kb currently
assumes the starter source is the first item in seed_template's
result.source_ids which can break if template source order changes; update
seed_starter_kb to locate the starter source id by matching the seeded source
whose text equals STARTER_SOURCE_TEXT (or the "starter" source spec) from
seed_template's returned metadata instead of using result.source_ids[0], keeping
the rest of the StarterSeedResult construction (claim_id=STARTER_CLAIM_ID,
created_source/created_claim flags) unchanged; reference seed_template,
seed_starter_kb, STARTER_CLAIM_ID, STARTER_SOURCE_TEXT, and result.source_ids
when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/vouch/onboarding.py`:
- Around line 71-100: The nested list fields are still mutable which lets
callers mutate shared data (e.g., _GITTENSOR_TAGS, Template.sources/claims,
_SourceSpec.tags, _ClaimSpec.source_keys/_ClaimSpec.tags) and can break
seed_template (KeyError at seed_template line 314); fix by making these
collections immutable: change the dataclass fields in _SourceSpec, _ClaimSpec
and Template from list[...] to tuple[...] (e.g., tags: tuple[str, ...],
source_keys: tuple[str, ...], sources: tuple[_SourceSpec, ...], claims:
tuple[_ClaimSpec, ...]) and replace the shared _GITTENSOR_TAGS list with a
tuple; ensure all Template and spec constructions pass tuples (or wrap existing
lists with tuple(...)) so TEMPLATES contains deeply immutable structures while
keeping the dataclasses frozen.

---

Nitpick comments:
In `@src/vouch/onboarding.py`:
- Around line 353-362: seed_starter_kb currently assumes the starter source is
the first item in seed_template's result.source_ids which can break if template
source order changes; update seed_starter_kb to locate the starter source id by
matching the seeded source whose text equals STARTER_SOURCE_TEXT (or the
"starter" source spec) from seed_template's returned metadata instead of using
result.source_ids[0], keeping the rest of the StarterSeedResult construction
(claim_id=STARTER_CLAIM_ID, created_source/created_claim flags) unchanged;
reference seed_template, seed_starter_kb, STARTER_CLAIM_ID, STARTER_SOURCE_TEXT,
and result.source_ids when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c0c2482-4c3c-4117-843a-97276f83eb70

📥 Commits

Reviewing files that changed from the base of the PR and between 3beb821 and af38494.

📒 Files selected for processing (3)
  • src/vouch/cli.py
  • src/vouch/onboarding.py
  • tests/test_onboarding.py

Comment thread src/vouch/onboarding.py Outdated
Comment on lines +71 to +100
@dataclass(frozen=True)
class _SourceSpec:
"""A source to seed. `key` wires claims to this source within a template."""

key: str
title: str
text: str
locator: str
tags: list[str] = field(default_factory=list)


@dataclass(frozen=True)
class _ClaimSpec:
"""A claim to seed, citing one or more sources by their `_SourceSpec.key`."""

id: str
text: str
type: ClaimType
status: ClaimStatus
confidence: float
source_keys: list[str]
tags: list[str] = field(default_factory=list)


@dataclass(frozen=True)
class Template:
name: str
description: str
sources: list[_SourceSpec]
claims: list[_ClaimSpec]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Python dataclasses, does @DataClass(frozen=True) prevent mutation of nested list fields, or are list attributes still mutable unless they are replaced with immutable types like tuple?

💡 Result:

In Python dataclasses, the frozen=True parameter does not prevent mutation of nested mutable objects, such as lists or dictionaries [1][2]. When you define a dataclass with frozen=True, the decorator adds setattr and delattr methods to the class that raise a FrozenInstanceError if you attempt to assign a new value to a field or delete one [1][3]. However, this only protects the dataclass instance itself from reassignment at the top level [2]. It does not provide deep immutability [1][3]. If a field contains a mutable object (like a list), you can still modify the contents of that object in place (e.g., using.append or index assignment) because these operations do not involve assigning to the dataclass attribute itself; they merely mutate the object the attribute references [4]. To achieve true immutability for such fields, you must replace the mutable type with an immutable alternative, such as a tuple [4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/vouch/onboarding.py"

# Show the relevant definitions near the template/dataclasses section
nl -ba "$FILE" | sed -n '1,220p' | sed -n '60,180p'
nl -ba "$FILE" | sed -n '180,330p'

# Locate where _GITTENSOR_TAGS and TEMPLATES are defined/used
rg -n "_GITTENSOR_TAGS|TEMPLATES|available_templates\(|seed_template\(|seed_starter_kb\(" "$FILE"

# Show the seed_template and seed_starter_kb implementations (around likely failure line ~314 per comment)
nl -ba "$FILE" | sed -n '280,380p'

Repository: vouchdev/vouch

Length of output: 101


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/vouch/onboarding.py"

# Print file with line numbers (using awk)
awk '{print FNR "\t" $0}' "$FILE" | sed -n '1,220p'
awk '{print FNR "\t" $0}' "$FILE" | sed -n '220,420p'

# Targeted searches for the specific concerns
rg -n "_GITTENSOR_TAGS|TEMPLATES|available_templates\(|seed_template\(|seed_starter_kb\(" "$FILE"

Repository: vouchdev/vouch

Length of output: 15196


Make the exported template registry deeply immutable.

@dataclass(frozen=True) here only blocks reassigning the dataclass fields; it does not make nested list[...] fields immutable. In src/vouch/onboarding.py, _SourceSpec.tags, _ClaimSpec.source_keys, _ClaimSpec.tags, Template.sources, and Template.claims are mutable lists, and _GITTENSOR_TAGS is a shared mutable list reused across multiple specs. Since TEMPLATES is exported as a mutable dict, a caller can mutate these lists in-place and affect later seed_template() runs; if claim_spec.source_keys no longer matches the written sources, the code can raise a KeyError at line 314 after sources were already stored.

♻️ Proposed direction
-from dataclasses import dataclass, field
+from dataclasses import dataclass
+from types import MappingProxyType
+from typing import Mapping

 `@dataclass`(frozen=True)
 class _SourceSpec:
@@
-    tags: list[str] = field(default_factory=list)
+    tags: tuple[str, ...] = ()

 `@dataclass`(frozen=True)
 class _ClaimSpec:
@@
-    source_keys: list[str]
-    tags: list[str] = field(default_factory=list)
+    source_keys: tuple[str, ...]
+    tags: tuple[str, ...] = ()

 `@dataclass`(frozen=True)
 class Template:
@@
-    sources: list[_SourceSpec]
-    claims: list[_ClaimSpec]
+    sources: tuple[_SourceSpec, ...]
+    claims: tuple[_ClaimSpec, ...]

-_GITTENSOR_TAGS = ["gittensor", "sn74", "scoring"]
+_GITTENSOR_TAGS = ("gittensor", "sn74", "scoring")

-TEMPLATES: dict[str, Template] = {
+TEMPLATES: Mapping[str, Template] = MappingProxyType({
     ...
-}
+})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/vouch/onboarding.py` around lines 71 - 100, The nested list fields are
still mutable which lets callers mutate shared data (e.g., _GITTENSOR_TAGS,
Template.sources/claims, _SourceSpec.tags,
_ClaimSpec.source_keys/_ClaimSpec.tags) and can break seed_template (KeyError at
seed_template line 314); fix by making these collections immutable: change the
dataclass fields in _SourceSpec, _ClaimSpec and Template from list[...] to
tuple[...] (e.g., tags: tuple[str, ...], source_keys: tuple[str, ...], sources:
tuple[_SourceSpec, ...], claims: tuple[_ClaimSpec, ...]) and replace the shared
_GITTENSOR_TAGS list with a tuple; ensure all Template and spec constructions
pass tuples (or wrap existing lists with tuple(...)) so TEMPLATES contains
deeply immutable structures while keeping the dataclasses frozen.

@plind-junior

Copy link
Copy Markdown
Member

Nice one — the template registry is clean and the gittensor pack covers everything #132 listed. Idempotent re-init, back-compat wrapper kept, good tests (including the vouch doctor check). Scoping the gittensor-repo bits (.vouch/, .mcp.json, CONTRIBUTING) out of this PR was the right move.

A few things before merge:

  • CHANGELOG — the PR checklist wants an ## [Unreleased] entry and the last onboarding change (epic: make vouch friendlier and more useful out of the box #54) set that precedent. Just add a one-liner. (This is the only real blocker.)
  • The gittensor claims are saved as status=STABLE, but the seed source itself says "re-verify and supersede these." STABLE says "settled," which is the opposite — maybe seed them as WORKING so the KB is honest about them being unverified.
  • Tiny: seed_starter_kb does result.source_ids[0], which assumes a template has at least one source. Fine today, would blow up on a source-less template later.
  • Tiny: the "Seeded N claim(s) from X source(s)" line counts all sources, not just newly-created ones, so a partial re-seed reads a little off.

One question: init now adds data={"template": ...} to the kb.init audit event. The README treats audit-log shape as VEP-territory — it's just an additive field so probably fine, but worth a maintainer's nod since the PR says "no VEP needed."

Overall: 👍 once the CHANGELOG line is in — everything else is minor / a quick gut-check.

@dripsmvcp
dripsmvcp changed the base branch from main to test May 28, 2026 23:53
@dripsmvcp
dripsmvcp force-pushed the fix/132-gittensor-template branch from af38494 to 03d176f Compare May 29, 2026 03:40
@plind-junior
plind-junior merged commit 05d9ee7 into vouchdev:test May 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants