Tak — dokładnie tak bym to docelowo widział: Intract jako linter/validator kontraktów intencji uruchamiany przed commitem, a później jako jeden z validatorów w vallm.
Czyli nie tylko:
intract validate .ale też:
intract check --stagedalbo docelowo:
vallm intract --staged
vallm batch src --enable-intractW przesłanym opisie vallm już ma dobrą bazę pod takie wdrożenie: istnieje CLI vallm, batch validation, validator pipeline, BaseValidator, scoring pipeline, cache walidacji plików, validatorzy syntax/imports/security/semantic oraz pyqual.yaml z quality gates i narzędziami vallm_src / vallm_verify.
vallm powinien walidować jakość kodu wygenerowanego przez LLM:
syntax
imports
lint
complexity
security
regression
semantic
intract contracts
A Intract powinien być warstwą:
czy kod realizuje zadeklarowaną intencję?
czy zmieniony kod nie złamał kontraktu?
czy wymagane pod-intencje istnieją?
czy zmieniony fragment nie łamie forbid:network / forbid:write / forbid:db?
czy projekt zachowuje spójność intent.yaml?
Czyli Intract w vallm powinien działać jak:
linter kontraktów intencji
a nie jako osobny eksperyment.
Najważniejszy tryb.
vallm intract --stagedalbo:
intract check --stagedDziała tylko na plikach z:
git diff --cached --name-only --diff-filter=ACMRCzyli przed commitem sprawdza tylko to, co realnie idzie do commita.
Waliduje:
1. zmienione pliki,
2. zmienione funkcje,
3. zmienione kontrakty @intract.v1,
4. zmiany w intent.yaml,
5. naruszenia forbid,
6. brak wymaganych require,
7. minimalne pokrycie kontraktami dla zmienionych fragmentów.
Do pracy na branchu:
vallm intract --changed --base mainSprawdza:
git diff --name-only main...HEADDobre do CI na pull request.
Do pełnej walidacji:
vallm intract src --recursivealbo:
intract validate .Sprawdza cały projekt, graf intencji, intent.yaml, pokrycie i naruszenia.
Najbardziej zaawansowany:
vallm intract --staged --hunksLogika:
1. pobierz git diff --cached --unified=0,
2. znajdź zmienione zakresy linii,
3. znajdź kontrakt najbliższy zakresowi,
4. jeśli zmieniona linia należy do funkcji z kontraktem, waliduj całą funkcję,
5. jeśli zmieniono intent.yaml, waliduj cały graf projektu.
W pre-commit Intract powinien być szybki i przewidywalny.
Proponowana polityka:
intract:
mode: staged
fail_on:
- violation
- missing_required_p1
- invalid_manifest
warn_on:
- partial
- missing_contract
- low_coverage
require_contract_for:
- changed_public_function
- changed_security_code
- changed_api_handler
ignore:
- tests/**
- docs/**Czyli commit blokujesz tylko wtedy, gdy:
1. kod łamie forbid,
2. zmieniono kontrakt i jest niepoprawny,
3. brakuje wymaganej intencji P1,
4. intent.yaml jest niespójny,
5. zmieniona funkcja krytyczna nie ma kontraktu.
Nie blokujesz od razu wszystkiego, bo na początku byłoby za dużo tarcia.
Na start zostawić Intract jako niezależną paczkę:
[project.optional-dependencies]
intract = ["intract>=0.1.0"]W vallm:
pip install vallm[intract]Plus:
try:
import intract
except ImportError:
intract = NoneTo minimalizuje ryzyko.
Dodać plik:
src/vallm/validators/intract.py
Klasa:
from vallm.validators.base import BaseValidator
from vallm.scoring import ValidationResult, Issue, Severity
class IntractValidator(BaseValidator):
name = "intract"
tier = 2
def validate(self, proposal, context):
...W środku:
from intract.project import validate_sourcesi mapowanie wyników Intract na wyniki vallm.
W src/vallm/scoring.py istnieje pipeline inicjalizacji validatorów i domyślne validatory. Tam trzeba dopiąć IntractValidator jako opcjonalny validator, tak jak obecne syntax/imports/security/semantic.
Przykładowo:
if settings.enable_intract:
validators.append(IntractValidator(settings))W src/vallm/config.py dodać:
VALLM_ENABLE_INTRACT: bool = False
VALLM_INTRACT_MANIFEST: str = "intent.yaml"
VALLM_INTRACT_MODE: str = "changed"
VALLM_INTRACT_FAIL_ON: str = "violation,missing_required_p1,invalid_manifest"
VALLM_INTRACT_MIN_CHANGED_COVERAGE: float = 0.0
VALLM_INTRACT_REQUIRE_CHANGED_CONTRACTS: bool = False
VALLM_INTRACT_ALLOW_MISSING_CONTRACTS: bool = TrueW .env.example:
VALLM_ENABLE_INTRACT=false
VALLM_INTRACT_MANIFEST=intent.yaml
VALLM_INTRACT_MODE=changed
VALLM_INTRACT_FAIL_ON=violation,missing_required_p1,invalid_manifest
VALLM_INTRACT_MIN_CHANGED_COVERAGE=0
VALLM_INTRACT_REQUIRE_CHANGED_CONTRACTS=falseNa początku ENABLE_INTRACT=false, żeby nie rozwalić istniejącego flow.
Obecny vallm ma validate_command, check_command, batch_command, info_command, a batch obsługuje ścieżki, recursive, include/exclude, semantic/security/regression itd.
Dodałbym nowy command:
vallm intract .Opcje:
vallm intract . --recursive
vallm intract . --manifest intent.yaml
vallm intract . --staged
vallm intract . --changed --base main
vallm intract . --format json
vallm intract . --fail-on violation
vallm intract . --show-coverageOraz rozszerzyłbym batch:
vallm batch src --enable-intractDla pre-commit:
vallm intract --staged --format textDodać plik:
.pre-commit-hooks.yaml
Treść:
- id: vallm-intract
name: vallm intract contracts
entry: vallm intract --staged
language: python
pass_filenames: false
stages: [pre-commit]Przykład użycia w projekcie:
repos:
- repo: local
hooks:
- id: vallm-intract
name: vallm intract contracts
entry: vallm intract --staged
language: system
pass_filenames: falseDlaczego pass_filenames: false?
Bo Intract powinien sam użyć:
git diff --cached --name-only
git diff --cached --unified=0wtedy ma pełną kontrolę nad staged changes.
git diff --cached --name-only --diff-filter=ACMRgit diff --cached --unified=0 -- <file>Jeśli zmieniono intent.yaml:
waliduj cały graf projektu.
Jeśli zmieniono plik z @intract:
waliduj kontrakty w tym pliku.
Jeśli zmieniono funkcję z kontraktem:
waliduj całą funkcję.
Jeśli zmieniono fragment bez kontraktu:
sprawdź, czy dziedziczy kontrakt z file-level albo manifestu.
Jeśli plik jest nowy:
sprawdź, czy powinien mieć kontrakt według polityki.
Przykład:
INTRACT FAILED
Changed files: 3
Contracts checked: 5
Passed: 3
Partial: 1
Violations: 1
Violation:
src/auth/permissions.py:12
validate.user_permission
Declared forbid:network, but requests.get was detected.
Fix:
- remove network call, or
- change contract effect/forbid if network is intended
vallm ma własne Issue, Severity, ValidationResult, PipelineResult w src/vallm/scoring.py.
Mapowanie:
| Intract | vallm |
|---|---|
pass |
score 1.0 |
partial |
warning / medium |
fail |
error |
violation |
error / critical |
unknown |
info / warning |
Przykład adaptera:
def map_intract_result(result) -> Issue:
if result.status == "violation":
severity = Severity.ERROR
elif result.status == "fail":
severity = Severity.ERROR
elif result.status == "partial":
severity = Severity.WARNING
else:
severity = Severity.INFO
return Issue(
rule="intract.contract",
message=f"{result.contract}: {result.status}",
severity=severity,
line=result.lines[0] if result.lines else None,
filename=result.file_path,
)Score validatora:
score = passed / totalalbo ostrzej:
if any(violation):
score = 0.0
elif any(fail):
score = 0.4
elif any(partial):
score = 0.7
else:
score = 1.0W pyqual.yaml vallm już ma metrykę:
vallm_pass_min: 90oraz custom tools vallm_src i vallm_verify, które uruchamiają vallm batch na src i weryfikację po fixach.
Dodałbym nową metrykę:
metrics:
vallm_pass_min: 90
intract_pass_min: 90
intract_violations_max: 0
intract_missing_p1_max: 0I stage:
custom_tools:
- name: intract_contracts
binary: .venv/bin/vallm
command: >-
.venv/bin/vallm intract {workdir}/src
--recursive
--manifest {workdir}/intent.yaml
--format toon
--output ./project/intract
output: ./project/intract/contracts.toon
allow_failure: false
stages:
- name: intract
tool: intract_contracts
optional: false
timeout: 300Albo w wersji przejściowej:
- name: intract
run: .venv/bin/intract validate . --manifest intent.yaml --json > .pyqual/intract.json
when: alwaysvallm ma już BatchProcessor, który buduje listę plików, filtruje include/exclude, obsługuje gitignore, pokazuje progress i przetwarza pliki równolegle.
Nie pisałbym tego drugi raz.
Zamiast tego:
src/vallm/cli/batch_processor_impl.py
dodać:
enable_intract: bool = False
intract_manifest: str | None = Nonei w _validate_single_file / validate_single_file dołączyć IntractValidator.
Ale uwaga: dla manifestu projektowego nie wystarczy pojedynczy plik, bo require wymaga grafu. Dlatego:
file-level validation → w batch per file
project graph validation → osobny krok po batch
Czyli batch powinien mieć dwa etapy:
1. validate every file
2. if enable_intract_project_graph:
validate manifest + graph once
To jest ważne architektonicznie.
Działa jak zwykły validator vallm:
Proposal(code, filename) → ValidationResult
Sprawdza:
@intract w danym pliku
forbid
input/output
return
lokalne kontrakty
Plik:
src/vallm/validators/intract.py
Działa na całym repo:
Project root + intent.yaml + changed files → ProjectReport
Sprawdza:
require
graf intencji
coverage
missing P1
duplikaty intencji
zmiany staged
Plik:
src/vallm/core/intract_project.py
albo:
src/vallm/validators/intract_project.py
Nie mieszać tych dwóch w jednej klasie.
Docelowo warto dodać:
src/vallm/core/git_diff.py
Funkcje:
def get_staged_files() -> list[Path]:
...
def get_changed_files(base: str = "main") -> list[Path]:
...
def get_staged_hunks(file: Path) -> list[ChangedHunk]:
...
def changed_contracts_in_file(file: Path, hunks: list[ChangedHunk]) -> list[Contract]:
...
def touched_contract_scope(file: Path, hunk: ChangedHunk) -> Scope:
...Zasada:
Jeśli zmiana dotyka funkcji, waliduj funkcję.
Jeśli zmiana dotyka kontraktu, waliduj kontrakt.
Jeśli zmiana dotyka intent.yaml, waliduj projekt.
Jeśli zmiana dotyka importów/efektów, sprawdź forbid.
To sprawi, że Intract będzie szybki jak linter.
Dodać plik:
intract.toml
albo sekcję w pyproject.toml:
[tool.intract]
manifest = "intent.yaml"
mode = "staged"
min_changed_coverage = 0
require_contracts_for_public_functions = false
fail_on = [
"violation",
"invalid_manifest",
"missing_required_p1"
]
warn_on = [
"partial",
"missing_contract",
"unknown"
]
ignore = [
"tests/**",
"docs/**",
"examples/**"
]Dla vallm:
[tool.vallm.intract]
enabled = true
manifest = "intent.yaml"
mode = "staged"
fail_on = ["violation", "missing_required_p1"]intract scan .
intract validate .
intract validate . --manifest intent.yaml
intract check --staged
intract check --changed --base main
intract coverage .
intract graph . --format mermaid
intract duplicates .vallm intract --staged
vallm intract . --recursive --manifest intent.yaml
vallm batch src --enable-intract
vallm check --enable-intractpre-commit run vallm-intractvallm intract --changed --base origin/main --format jsonDo pyproject.toml vallm:
[project.optional-dependencies]
intract = ["intract>=0.1.0"]Do dokumentacji:
pip install -e ".[intract]"Dodać:
src/vallm/cli/intract_command.py
Komenda:
vallm intract .Na początku może tylko wywoływać API Intract.
Dodać:
src/vallm/validators/intract.py
i opcję:
vallm validate --enable-intractDodać:
vallm batch src --enable-intractdo istniejącego batch command, który już obsługuje ścieżki, recursive, include/exclude, format i fail-fast.
Dodać:
vallm intract --stagedoraz .pre-commit-hooks.yaml.
Dodać walidację:
vallm intract . --project-graphz intent.yaml.
Dodać stage intract do pyqual.yaml.
vallm ma MCP tools dla validate_syntax, validate_imports, validate_security i validate_code.
Dodać narzędzia:
validate_intent_contracts
validate_intract_project
validate_intract_staged
src/vallm/
validators/
intract.py
core/
intract_adapter.py
intract_project.py
git_diff.py
cli/
intract_command.py
command_handlers.py
reporters/
intract_reporter.py
tests/
test_intract_validator.py
test_intract_cli.py
test_intract_staged.py
test_intract_manifest.py
.pre-commit-hooks.yaml
Jeśli nie chcesz tworzyć nowych katalogów, minimalny MVP:
src/vallm/validators/intract.py
src/vallm/cli/command_handlers.py
src/vallm/config.py
tests/test_intract_validator.py
Nie robić z Intract od razu „twardego wymogu” dla całego projektu.
Najpierw:
warn-only
Potem:
fail only on violation
Potem:
fail on missing required P1
Dopiero na końcu:
coverage gates
Czyli kolejność:
1. ostrzegaj,
2. blokuj naruszenia,
3. blokuj brak P1,
4. wymagaj pokrycia kontraktami.
INTRACT CONTRACT CHECK
Mode: staged
Manifest: intent.yaml
Changed files:
- src/auth/permissions.py
- src/api/users.py
Checked contracts: 4
PASS
src/auth/permissions.py:12 validate.user_permission
PARTIAL
src/api/users.py:44 expose.user_api
missing: require:validate.user_input
VIOLATION
src/auth/permissions.py:12 validate.user_permission
forbid:network violated by requests.get(...)
Result: FAILED
Commit nie przechodzi, bo jest VIOLATION.
Dzisiaj vallm odpowiada głównie na pytanie:
czy kod jest poprawny składniowo, importowo, jakościowo, bezpieczeństwa, semantycznie?
Intract doda pytanie:
czy kod realizuje zadeklarowaną intencję?
To jest bardzo dobre uzupełnienie vallm, bo walidacja LLM-generated code nie powinna kończyć się na składni i lintingu. Kod może być poprawny technicznie, ale robić nie to, co miał robić. Intract jest warstwą, która formalizuje „co miało być zrobione”.
Dodać do Intract:
check --staged
check --changed --base main
Dodać do vallm:
src/vallm/validators/intract.py
--enable-intract
Dodać:
vallm intract --staged
.pre-commit-hooks.yaml
Dodać:
intent.yaml graph validation
missing P1 gates
Dodać do pyqual.yaml:
intract_pass_min
intract_violations_max
Dodać MCP tools i raporty JSON/TOON/SARIF.
Tak — Intract powinien działać jak pre-commit linter kontraktów intencji, a w vallm powinien być wdrożony jako:
1. osobny CLI command: vallm intract,
2. opcjonalny validator: --enable-intract,
3. stage w pyqual,
4. pre-commit hook,
5. project graph validator dla intent.yaml,
6. później MCP tool.
To dobrze pasuje do architektury vallm, bo projekt już ma batch validation, validator base, scoring pipeline, CLI, pyqual quality gates i MCP tools.