Skip to content

Commit a2e0df4

Browse files
Antigravity Agentclaude
andcommitted
feat(spec): Spec Enricher — read .zig, enrich .tri (#69)
- specs/tri/spec_enricher.tri: VIBEE spec, vibee gen + ast-check pass - src/tri/tri_spec_enricher.zig: extract types/fns/tests from .zig → update .tri - CLI: tri enrich <spec> / tri enrich --all / tri enrich --dry-run - 9/9 unit tests pass, 334/344 specs enrichable (97%) - Wired into tri_utils.zig (Command enum) + main.zig (dispatch) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2f60292 commit a2e0df4

4 files changed

Lines changed: 772 additions & 0 deletions

File tree

specs/tri/spec_enricher.tri

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# ═══════════════════════════════════════════════════════════════════════════════
2+
# VIBEE Specification — Spec Enricher
3+
# ═══════════════════════════════════════════════════════════════════════════════
4+
# φ² + 1/φ² = 3 = TRINITY
5+
# Issue #69: Read .zig files, enrich .tri specs
6+
# ═══════════════════════════════════════════════════════════════════════════════
7+
8+
name: spec_enricher
9+
version: "1.0.0"
10+
language: zig
11+
module: spec_enricher
12+
13+
description: |
14+
Spec Enricher — reads .zig source files and enriches matching .tri specs.
15+
Extracts actual type definitions, public function signatures, and test names
16+
from Zig code. Updates the spec without overwriting manual descriptions.
17+
18+
# ═══════════════════════════════════════════════════════════════════════════════
19+
# TYPE SYSTEM
20+
# ═══════════════════════════════════════════════════════════════════════════════
21+
22+
types:
23+
ExtractedType:
24+
fields:
25+
name: String
26+
kind: String
27+
field_names: List(String)
28+
29+
ExtractedFunction:
30+
fields:
31+
name: String
32+
params: List(String)
33+
return_type: String
34+
is_public: Bool
35+
36+
ExtractedTest:
37+
fields:
38+
name: String
39+
40+
EnrichResult:
41+
fields:
42+
spec_path: String
43+
zig_path: String
44+
types_found: Int
45+
functions_found: Int
46+
tests_found: Int
47+
updated: Bool
48+
49+
# ═══════════════════════════════════════════════════════════════════════════════
50+
# BEHAVIORS
51+
# ═══════════════════════════════════════════════════════════════════════════════
52+
53+
behaviors:
54+
find_zig_source:
55+
description: "Find corresponding .zig file for a .tri spec"
56+
inputs:
57+
- spec_path: String
58+
output: Optional(String)
59+
steps:
60+
- Extract stem from spec_path
61+
- Check generated/{stem}.zig
62+
- Check src/tri/{stem}.zig
63+
- Check src/tri/tri_{stem}.zig
64+
- Return first found or null
65+
66+
extract_types:
67+
description: "Extract pub struct/enum/union definitions from Zig source"
68+
inputs:
69+
- source: String
70+
output: List(ExtractedType)
71+
steps:
72+
- Scan for "pub const X = struct {"
73+
- Scan for "pub const X = enum {"
74+
- Scan for "pub const X = union {"
75+
- Extract field names from struct bodies
76+
- Return list of ExtractedType
77+
78+
extract_functions:
79+
description: "Extract pub fn signatures from Zig source"
80+
inputs:
81+
- source: String
82+
output: List(ExtractedFunction)
83+
steps:
84+
- Scan for "pub fn name("
85+
- Parse parameter list
86+
- Parse return type
87+
- Return list of ExtractedFunction
88+
89+
extract_tests:
90+
description: "Extract test block names from Zig source"
91+
inputs:
92+
- source: String
93+
output: List(ExtractedTest)
94+
steps:
95+
- Scan for 'test "name"'
96+
- Extract test name string
97+
- Return list of ExtractedTest
98+
99+
enrich_spec:
100+
description: "Read .zig, extract info, update .tri spec"
101+
inputs:
102+
- spec_path: String
103+
output: EnrichResult
104+
steps:
105+
- Find corresponding .zig source
106+
- Read .zig file content
107+
- Extract types, functions, tests
108+
- Read existing .tri spec
109+
- Merge new findings (preserve descriptions)
110+
- Write updated .tri
111+
112+
run_enrich_command:
113+
description: "CLI entry: tri enrich <spec.tri>"
114+
inputs:
115+
- args: List(String)
116+
output: Void
117+
steps:
118+
- Parse spec_path from args
119+
- Call enrich_spec
120+
- Print enrichment report
121+
122+
# ═══════════════════════════════════════════════════════════════════════════════
123+
# CONSTRAINTS
124+
# ═══════════════════════════════════════════════════════════════════════════════
125+
126+
constraints:
127+
- Never overwrite manually-written descriptions
128+
- Preserve existing type/behavior ordering
129+
- Output must pass vibee validate
130+
- Only extract pub (public) items from .zig
131+
- Handle missing .zig gracefully (skip with warning)
132+
133+
# ═══════════════════════════════════════════════════════════════════════════════
134+
# TESTS
135+
# ═══════════════════════════════════════════════════════════════════════════════
136+
137+
tests:
138+
- name: "extractTypes finds struct"
139+
input: {source: "pub const Foo = struct { x: u32 };"}
140+
expected: {types_len: 1, name: "Foo", kind: "struct"}
141+
142+
- name: "extractFunctions finds pub fn"
143+
input: {source: "pub fn doStuff(a: u32) void {}"}
144+
expected: {fns_len: 1, name: "doStuff"}
145+
146+
- name: "extractTests finds test blocks"
147+
input: {source: "test \"my test\" { }"}
148+
expected: {tests_len: 1, name: "my test"}
149+
150+
- name: "findZigSource checks generated/ first"
151+
input: {spec_path: "specs/tri/vsa.tri"}
152+
expected: {zig_path_contains: "vsa.zig"}

src/tri/main.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ pub fn main() !void {
579579
.mcp => try tri_register.runCommand(allocator, "mcp", cmd_args),
580580
// Spec Linter (Issue #68)
581581
.lint => try commands.runLintCommand(allocator, cmd_args),
582+
// Spec Enricher (Issue #69)
583+
.enrich => {
584+
const spec_enricher = @import("tri_spec_enricher.zig");
585+
try spec_enricher.runEnrichCommand(allocator, cmd_args);
586+
},
582587
// GitHub Integration (Protocol v2)
583588
.github => try github_commands.runGithubCommand(allocator, cmd_args, false),
584589
// .monitor => { // TODO: Add monitor to Command enum in tri_utils.zig
@@ -1059,6 +1064,13 @@ fn dispatchCommand(
10591064
.lint => commands.runLintCommand(allocator, cmd_args) catch |err| {
10601065
std.debug.print("Lint error: {}\n", .{err});
10611066
},
1067+
// Spec Enricher (Issue #69)
1068+
.enrich => {
1069+
const spec_enricher = @import("tri_spec_enricher.zig");
1070+
spec_enricher.runEnrichCommand(allocator, cmd_args) catch |err| {
1071+
std.debug.print("Enrich error: {}\n", .{err});
1072+
};
1073+
},
10621074
// GitHub Integration (Protocol v2)
10631075
.github => github_commands.runGithubCommand(allocator, cmd_args, state.dry_run) catch |err| {
10641076
std.debug.print("GitHub error: {}\n", .{err});

0 commit comments

Comments
 (0)