Repository navigation
feat(ticket-035): versioned bounded projections for intent retrieval - #34
Conversation
Add the projections export format: projections.json, a deterministic, versioned catalog of source symbols (module/class/function) with provenance (symbol, file, line), per-record and whole-document sha256 digests, producer version pinning and a hard 2048-record cap with a truncated flag. Downstream consumers (semcod/search canary) reuse this artifact instead of importing analyzer internals. - code2llm/exporters/projections_exporter.py: build_projection() + ProjectionsExporter registered as 'projections' - CLI: -f projections; FORMAT_FILENAMES/DRY_RUN/LABELS wiring - tests/test_projections_exporter.py: determinism (byte-identical rebuilds), provenance, bounds, truncation, version stamping, registry and CLI help (8 tests; suite 376 passed) - Measured on code2llm/ itself (180 files): 459 KB vs 7 163 KB analysis.json (15.6x smaller), export 0.02 s, 1401 symbols (1125 fn / 96 cls / 180 mod), byte-deterministic across runs Cache invalidation: producer.version + record digests change on any analyzer/version drift; PersistentCache keys already bind __version__. Part of #25 Co-authored-by: Koru Agent <agent@coru.dev>
There was a problem hiding this comment.
Validator approval after policy checks for exact head 69c8d3f2a832497b836fb7542e40daa555ad41f4.
Ticket: ticket-035
Correlation ID: plf-035-pr34
Model: gemini/gemini-3.8-flash
Reviewed diff chunks: 2
Advisory LLM verdict: APPROVE
Advisory summary: Reviewed all 2 diff chunk(s). Implements the bounded symbol catalog exporter (projections.json, schema code2llm.projection/v1) for intent retrieval and external indexers. Determinism, bounds, provenance, CLI wiring, and test coverage are cleanly integrated. | Tests for the new projections exporter thoroughly verify determinism, digest stability, record sorting, bound enforcement (field and record caps), canonical JSON serialization, registry integration, and CLI help output. Required CI checks pass.
Advisory findings: none
The LLM output above is advisory and was not used as the approval trust root.
Semantic review prerequisite: not_required; policy 676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7.
Actual PR impact radar
Exact range: e23613eaee5160c7450914e1f93f6b9329e1aa28...69c8d3f2a832497b836fb7542e40daa555ad41f4
Change digest: 13af8f2afd70cc2497e28685e28342bdefd7af467d3d3ca5c68fdb014cddae83
Score: 76/100 (L), estimated 92 min, split recommended: true
Affected services/components: repository-wide/unclassified
Machine-readable radar JSONL and SVG
{"actual_change":{"additions":293,"base_sha":"e23613eaee5160c7450914e1f93f6b9329e1aa28","binary_files":0,"categories":{"code":5,"docs":1,"tests":1},"change_digest":"13af8f2afd70cc2497e28685e28342bdefd7af467d3d3ca5c68fdb014cddae83","comparison":"e23613eaee5160c7450914e1f93f6b9329e1aa28...69c8d3f2a832497b836fb7542e40daa555ad41f4","deletions":1,"file_count":7,"files":["README.md","code2llm/cli_exports/formats.py","code2llm/cli_exports/orchestrator_constants.py","code2llm/cli_parser.py","code2llm/exporters/__init__.py","code2llm/exporters/projections_exporter.py","tests/test_projections_exporter.py"],"head_sha":"69c8d3f2a832497b836fb7542e40daa555ad41f4","service_count":0,"services":[]},"assessment_mode":"observed-pr","axes":{"coupling":5,"delivery":4,"scope":5,"uncertainty":3,"validation":2},"complexity":"L","confidence":0.9,"diagnostics":["RADAR-ACCEPTANCE-MISSING","RADAR-BUDGET-EXCEEDED"],"estimate":{"budget_minutes":30,"minutes":92,"within_budget":false},"impact":{"components":["boundy","code2llm","code2llm.projection","module","repository-root","semcod","tests"],"files":["README.md","boundy/truncation","code2llm.projection/v1","code2llm/cli_exports/formats.py","code2llm/cli_exports/orchestrator_constants.py","code2llm/cli_parser.py","code2llm/exporters/__init__.py","code2llm/exporters/projections_exporter.py","module/class/function","semcod/search","tests/test_projections_exporter.py"],"public_interfaces":[],"runtime_dependencies":0},"schema":"subactor.ticket-radar/v1","score":76,"split":{"parts":[{"estimated_minutes":12,"name":"Implement boundy","scope":["boundy"]},{"estimated_minutes":12,"name":"Implement code2llm","scope":["code2llm"]},{"estimated_minutes":12,"name":"Implement code2llm.projection","scope":["code2llm.projection"]},{"estimated_minutes":12,"name":"Implement module","scope":["module"]},{"estimated_minutes":12,"name":"Implement repository-root","scope":["repository-root"]},{"estimated_minutes":15,"name":"Validate and project to trackers","scope":["tests","planfile","github/gitlab/jira projections"]}],"reason":"estimated_minutes_exceed_budget","recommended":true},"standards":[{"id":"wellmanifest/dsl","revision":"6c60fc4e0dd1f1bb74f46a7745e28019908d1203","version":"0.1.0-dev"},{"id":"wellmanifest/ticket-lifecycle","revision":"5bf581907a87b46a13a73e6c033d3abe4d9a306f","version":"0.1.0-dev"},{"id":"wellmanifest/git-lifecycle","revision":"7d77d4b7af57e69bc75c3a0290b3a4805c5c4438","version":"0.2.0-dev"},{"id":"wellmanifest/logs","revision":"48c284ef7a069055c0bcb6b900147ce5e65f8b43","version":"0.3.0"}],"ticket_ref":"ticket-035"}<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img"><title>ticket-035: feat(ticket-035): versioned bounded projections for intent retrieval</title><rect width="128" height="128" rx="12" fill="#f8fafc"/><g stroke-width="1"><polygon points="64,55 72,61 69,71 59,71 56,61" fill="none" stroke="#d7dde5"/><polygon points="64,47 80,59 74,78 54,78 48,59" fill="none" stroke="#d7dde5"/><polygon points="64,38 89,56 79,85 49,85 39,56" fill="none" stroke="#d7dde5"/><polygon points="64,30 97,53 84,92 44,92 31,53" fill="none" stroke="#d7dde5"/><polygon points="64,21 105,51 89,99 39,99 23,51" fill="none" stroke="#d7dde5"/><line x1="64" y1="64" x2="64" y2="21" stroke="#aab4c0"/><line x1="64" y1="64" x2="105" y2="51" stroke="#aab4c0"/><line x1="64" y1="64" x2="89" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="39" y2="99" stroke="#aab4c0"/><line x1="64" y1="64" x2="23" y2="51" stroke="#aab4c0"/></g><polygon points="64,21 105,51 79,85 54,78 31,53" fill="#fb923c" fill-opacity="0.45" stroke="#c2410c" stroke-width="2"/><circle cx="64" cy="64" r="3" fill="#c2410c"/><g font-family="sans-serif" font-size="7" fill="#334155"><text x="64" y="11" text-anchor="middle">SCO</text><text x="114" y="48" text-anchor="middle">COU</text><text x="95" y="107" text-anchor="middle">UNC</text><text x="33" y="107" text-anchor="middle">VAL</text><text x="14" y="48" text-anchor="middle">DEL</text></g><text x="64" y="124" text-anchor="middle" font-family="sans-serif" font-size="8" fill="#0f172a">L · 92m</text></svg>DECISION D-035-5111
TICKET ticket-035
HEAD_SHA 69c8d3f2a832497b836fb7542e40daa555ad41f4
CORRELATION_ID plf-035-pr34
ACTOR agent:ifuri-validator-agent[bot]
APPLIED_RULE P-CORE-015
INPUT author_login = "tom-sapletta-com"
INPUT observed_checks = ["test (3.13)=PASS","test (3.10)=PASS"]
INPUT required_checks = ["test (3.10)","test (3.13)"]
INPUT required_checks_source = "protected registry (env/request)"
INPUT reviewer_login = "ifuri-validator-agent[bot]"
INPUT semantic_review_assessment = {"schema":"subactor.validator/semantic-review-assessment/v1","subject":{"repository":"semcod/code2llm","pull_request":34,"head_sha":"69c8d3f2a832497b836fb7542e40daa555ad41f4","base_sha":"e23613eaee5160c7450914e1f93f6b9329e1aa28","diff_sha256":"05fd793b1ca215be1e8de1385aaa7d160c6f56652eb059d8e7fff5a6a8cd341d"},"policy":{"policy_schema":"subactor.validator/semantic-review-policy/v1","policy_version":1,"policy_sha256":"676cb4516bbfed2a000e40b9b1b6e4a430ecc761ec546aeb53d721a1905cfdd7","required":false,"critical_paths":[],"observed_paths":["README.md","code2llm/cli_exports/formats.py","code2llm/cli_exports/orchestrator_constants.py","code2llm/cli_parser.py","code2llm/exporters/__init__.py","code2llm/exporters/projections_exporter.py","tests/test_projections_exporter.py"]},"grounding":"full-diff-not-per-finding-proof","execution_authority":false,"status":"not_required","reason":null,"review_sha256":null,"unresolved":[]}
INPUT superseded_checks = []
INPUT ticket_radar_receipt = {"schema":"subactor.ticket-radar/v1","base_sha":"e23613eaee5160c7450914e1f93f6b9329e1aa28","head_sha":"69c8d3f2a832497b836fb7542e40daa555ad41f4","change_digest":"13af8f2afd70cc2497e28685e28342bdefd7af467d3d3ca5c68fdb014cddae83","score":76,"complexity":"L","estimated_minutes":92,"split_recommended":true,"services":[],"authority":"ADVISORY","promotion":"FORBIDDEN"}
VERDICT APPROVE AUTHORITY DETERMINISTIC
REJECTED REQUEST_CHANGES BECAUSE NO_UNSAFE_CHANGE_REASON_FOUND
ADVISORY llm_verdict = "APPROVE" MODEL "gemini/gemini-3.8-flash"
ASSERT VERDICT_AUTHORITY != "ADVISORY"
Part of #25 (PLF-035) — strona producenta kontraktu.
Co
Nowy format eksportu
-f projections→projections.json:code2llm.projection/v1+producer.version(pin wersji analizatora)symbol,file,linegenerated_atopcjonalne, poza digestem)stats.truncated, pola tnione do 200 znakówDlaczego artefakt, nie API
Issue #25: „Reuse … without copying analyzer implementation into search”. Reuse point = wersjonowany artefakt; konsument (canary w semcod/search) czyta JSON bez importów code2llm.
Pomiary (korpus: code2llm/, 180 plików)
1401 symboli (1125 funkcji / 96 klas / 180 modułów), bez truncation. Rebuild → byte-identical (cmp).
Testy
tests/test_projections_exporter.py(8): determinizm, proweniencja, boundy/truncation, wersjonowanie, registry, CLI helptest_analysis_cache_versionzielony — inwalidacja po__version__istnieje i jest testowana)Inwalidacja cache
PersistentCache/make_cache_keyjuż bindują__version__(test_analysis_cache_version)producer.versionlub digestów → reindex (fingerprint semcod/search)Następny krok (osobny PR w semcod/search): adapter
code2llm.projection/v1wintent_adapters.adapt()+REPORT_PATHS+FORMATS— canary konsumpcji.