The framework indexer now captures the members of composite types — struct fields (with their tags) and interface method sets — closing a gap where get_symbol/search_symbols could name a type but not describe its shape.
Type of change
Bug fix — non-breaking change that resolves an issue
New feature — non-breaking addition of functionality
Breaking change — alters existing behavior or public API
Documentation update
Refactor — no functional change, no new API surface
Test improvement
Description
Problem.formatNode truncates every declaration at the first {, so the index stored only the one-line header of each type. For a struct that meant the field names, types, and struct tags were dropped — e.g. nothing in the index revealed that db-postgresConfig.Host is set by env:"EINHERJAR_PG_HOST,required". For an interface it meant the method set was dropped — you could not learn what Provider requires. This surfaced in practice while wiring an app: the index could be asked "does Config have a DSN() method?" and "what env vars configure Postgres?" and answer neither. (The separate DSN()-not-found incident was a stale deployed index, not a builder bug — the builder already indexes methods, and a redeploy fixes it. This PR fixes the structural truncation that no redeploy would have cured.)
Approach. Extend the index schema with two optional, omitempty members on Symbol:
fields []Field — for struct types: name, type, raw struct tag (backticks stripped), doc, and an embedded flag.
methods []Method — for interface types: name, signature (without the leading func), doc; embedded interfaces included.
The builder fills these by inspecting each type's TypeSpec (*ast.StructType / *ast.InterfaceType) via small helpers, using a new non-truncating nodeString printer alongside the existing formatNode (which still produces the one-line header). search_symbols now also matches a query against field names/types/tags and interface method names/signatures, so an env-var key or a method name resolves to the declaring type. get_symbol needed no logic change — it already returns the whole Symbol.
Alternatives considered. Storing a single untruncated "full definition" string per symbol — rejected because it would drag in function bodies and is far less queryable than structured fields/methods (no search-by-tag).
Versioning / schema. Index SchemaVersion is intentionally unchanged (additive, omitempty fields — older consumers parse the new index unchanged). The release version is a minor bump, v0.2.0 (new non-breaking functionality over v0.1.1); CHANGELOG.md and RELEASE.md are set accordingly — adjust the 2026-06-10 date if the release commit lands on a different day.
Known limitations / follow-up. The committed data/index.json placeholder is untouched; the index is regenerated at image build (Dockerfile runs cmd/indexer), so the live service only gains the richer data after a rebuild/redeploy — please redeploy (this also clears the pre-existing stale-index issue). Generic type parameters and const values are out of scope here.
Testing
I added or updated tests that cover my changes
All tests pass locally — go test ./...
No formatting issues — gofmt -l . produces no output
No vet warnings — go vet ./... is clean
New internal/index/builder_test.go (the package had no tests before) builds a temp module fixture and asserts: struct fields with tags and docs, embedded fields, interface methods with signatures and docs, embedded interfaces, and search-by-struct-tag. Reindexing the live framework confirms db-postgres.Config now exposes all 12 fields with their EINHERJAR_PG_* tags (and Config.DSN), and Provider exposes GetExecutor/Begin/BeginTx/Ping/HandleError.
Checklist
At most one exported type per non-test .go file (CT-6) — new Field/Method types live in index.go beside the existing Symbol/Module/etc. type group; consistent with the file's established multi-type schema layout
No new external dependencies added without prior discussion in an issue — none added
Public API changes are reflected in CHANGELOG.md
Breaking changes include a migration note in the PR description above — n/a, non-breaking
## Summary
The framework indexer now captures the **members** of composite types — struct fields (with their tags) and interface method sets — closing a gap where `get_symbol`/`search_symbols` could name a type but not describe its shape.
---
## Type of change
- [ ] Bug fix — non-breaking change that resolves an issue
- [x] New feature — non-breaking addition of functionality
- [ ] Breaking change — alters existing behavior or public API
- [ ] Documentation update
- [ ] Refactor — no functional change, no new API surface
- [ ] Test improvement
---
## Description
**Problem.** `formatNode` truncates every declaration at the first `{`, so the index stored only the one-line header of each type. For a struct that meant the field names, types, and **struct tags were dropped** — e.g. nothing in the index revealed that `db-postgres` `Config.Host` is set by `env:"EINHERJAR_PG_HOST,required"`. For an interface it meant the **method set was dropped** — you could not learn what `Provider` requires. This surfaced in practice while wiring an app: the index could be asked "does `Config` have a `DSN()` method?" and "what env vars configure Postgres?" and answer neither. (The separate `DSN()`-not-found incident was a *stale deployed index*, not a builder bug — the builder already indexes methods, and a redeploy fixes it. This PR fixes the structural truncation that no redeploy would have cured.)
**Approach.** Extend the index schema with two optional, `omitempty` members on `Symbol`:
- `fields []Field` — for struct types: name, type, raw struct tag (backticks stripped), doc, and an `embedded` flag.
- `methods []Method` — for interface types: name, signature (without the leading `func`), doc; embedded interfaces included.
The builder fills these by inspecting each type's `TypeSpec` (`*ast.StructType` / `*ast.InterfaceType`) via small helpers, using a new non-truncating `nodeString` printer alongside the existing `formatNode` (which still produces the one-line header). `search_symbols` now also matches a query against field names/types/tags and interface method names/signatures, so an env-var key or a method name resolves to the declaring type. `get_symbol` needed no logic change — it already returns the whole `Symbol`.
**Alternatives considered.** Storing a single untruncated "full definition" string per symbol — rejected because it would drag in function bodies and is far less queryable than structured fields/methods (no search-by-tag).
**Versioning / schema.** Index `SchemaVersion` is intentionally **unchanged** (additive, `omitempty` fields — older consumers parse the new index unchanged). The *release* version is a **minor** bump, **v0.2.0** (new non-breaking functionality over v0.1.1); `CHANGELOG.md` and `RELEASE.md` are set accordingly — adjust the `2026-06-10` date if the release commit lands on a different day.
**Known limitations / follow-up.** The committed `data/index.json` placeholder is untouched; the index is regenerated at image build (`Dockerfile` runs `cmd/indexer`), so the live service only gains the richer data **after a rebuild/redeploy** — please redeploy (this also clears the pre-existing stale-index issue). Generic type parameters and const *values* are out of scope here.
---
## Testing
- [x] I added or updated tests that cover my changes
- [x] All tests pass locally — `go test ./...`
- [x] No formatting issues — `gofmt -l .` produces no output
- [x] No vet warnings — `go vet ./...` is clean
New `internal/index/builder_test.go` (the package had no tests before) builds a temp module fixture and asserts: struct fields with tags and docs, embedded fields, interface methods with signatures and docs, embedded interfaces, and search-by-struct-tag. Reindexing the live framework confirms `db-postgres.Config` now exposes all 12 fields with their `EINHERJAR_PG_*` tags (and `Config.DSN`), and `Provider` exposes `GetExecutor`/`Begin`/`BeginTx`/`Ping`/`HandleError`.
---
## Checklist
- [x] At most one exported type per non-test `.go` file (CT-6) — new `Field`/`Method` types live in `index.go` beside the existing `Symbol`/`Module`/etc. type group; consistent with the file's established multi-type schema layout
- [x] No new external dependencies added without prior discussion in an issue — none added
- [x] Public API changes are reflected in `CHANGELOG.md`
- [ ] Breaking changes include a migration note in the PR description above — n/a, non-breaking
---
Minor release. The indexer named composite types but could not describe
their shape: every declaration was truncated at the first brace, so a
struct symbol carried only its `type X struct` header and an interface
symbol only its `type X interface` header. Field names, field types, and
— most painfully — struct tags such as `env:"EINHERJAR_PG_HOST"` were
dropped, as were the method sets of every port interface. An assistant
could be told that `db-postgres` has a `Config` and a `Provider`, but not
what env vars configure the one or what methods the other requires. This
change captures both.
internal/index (schema):
- Symbol gains two optional fields. `fields` ([]Field) carries a struct's
field set — name, type, raw struct tag (surrounding backticks stripped),
doc comment, and an `embedded` marker. `methods` ([]Method) carries an
interface's method set — name, signature without the leading `func`, and
doc comment, including embedded interfaces. Both are omitempty and absent
for every other kind.
- SchemaVersion is deliberately unchanged. The two additions are additive
and omitempty, so an older consumer parses the new index unchanged; per
the existing rule the constant only bumps on a breaking format change.
internal/index (builder):
- collectSymbols now inspects each type's TypeSpec and, for a *ast.StructType
or *ast.InterfaceType, fills the new Symbol members. A grouped field
declaration (`x, y int`) yields one Field per name; an embedded field or
interface yields an entry with an empty name.
- New helpers: typeSpecType (underlying type expr of a lone type spec),
extractFields, extractIfaceMethods, fieldDoc (doc comment or trailing
line comment), and nodeString — a non-truncating printer used for field
types, tags, and method signatures, distinct from formatNode which keeps
truncating to produce the one-line header.
internal/index (search):
- matches() now also tests the query against struct field names, field
types, and struct tags, and against interface method names and
signatures. A query like an env-var key or a method name now resolves to
the type that declares it.
internal/tools:
- get_symbol and search_symbols descriptions updated to advertise the new
struct-field and interface-method coverage. No input/output schema change
beyond the additive Symbol fields, which get_symbol already returns whole.
internal/index (tests):
- New builder_test.go — the package previously had no tests. Builds a
temporary module fixture and asserts capture of struct fields (with tags
and docs), embedded fields, interface methods (with signatures and docs),
embedded interfaces, and discovery of a struct by one of its struct tags
(the failure mode that motivated the change).
Docs:
- CHANGELOG.md gains an [Unreleased] entry; README.md tool table updated to
state that get_symbol returns struct fields and interface methods and
that search_symbols matches fields, tags, and methods.
No new dependencies. The committed data/index.json placeholder is untouched
— the index is regenerated at image build (Dockerfile runs cmd/indexer),
so a deployment must be rebuilt to serve the richer index; a server still
running the prior image keeps serving the older, member-less one.
Rene Nochebuena
requested review from CoreDevelopers 2026-06-10 10:38:22 -06:00
Rene Nochebuena
requested review from Agents 2026-06-10 10:38:22 -06:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
The framework indexer now captures the members of composite types — struct fields (with their tags) and interface method sets — closing a gap where
get_symbol/search_symbolscould name a type but not describe its shape.Type of change
Description
Problem.
formatNodetruncates every declaration at the first{, so the index stored only the one-line header of each type. For a struct that meant the field names, types, and struct tags were dropped — e.g. nothing in the index revealed thatdb-postgresConfig.Hostis set byenv:"EINHERJAR_PG_HOST,required". For an interface it meant the method set was dropped — you could not learn whatProviderrequires. This surfaced in practice while wiring an app: the index could be asked "doesConfighave aDSN()method?" and "what env vars configure Postgres?" and answer neither. (The separateDSN()-not-found incident was a stale deployed index, not a builder bug — the builder already indexes methods, and a redeploy fixes it. This PR fixes the structural truncation that no redeploy would have cured.)Approach. Extend the index schema with two optional,
omitemptymembers onSymbol:fields []Field— for struct types: name, type, raw struct tag (backticks stripped), doc, and anembeddedflag.methods []Method— for interface types: name, signature (without the leadingfunc), doc; embedded interfaces included.The builder fills these by inspecting each type's
TypeSpec(*ast.StructType/*ast.InterfaceType) via small helpers, using a new non-truncatingnodeStringprinter alongside the existingformatNode(which still produces the one-line header).search_symbolsnow also matches a query against field names/types/tags and interface method names/signatures, so an env-var key or a method name resolves to the declaring type.get_symbolneeded no logic change — it already returns the wholeSymbol.Alternatives considered. Storing a single untruncated "full definition" string per symbol — rejected because it would drag in function bodies and is far less queryable than structured fields/methods (no search-by-tag).
Versioning / schema. Index
SchemaVersionis intentionally unchanged (additive,omitemptyfields — older consumers parse the new index unchanged). The release version is a minor bump, v0.2.0 (new non-breaking functionality over v0.1.1);CHANGELOG.mdandRELEASE.mdare set accordingly — adjust the2026-06-10date if the release commit lands on a different day.Known limitations / follow-up. The committed
data/index.jsonplaceholder is untouched; the index is regenerated at image build (Dockerfilerunscmd/indexer), so the live service only gains the richer data after a rebuild/redeploy — please redeploy (this also clears the pre-existing stale-index issue). Generic type parameters and const values are out of scope here.Testing
go test ./...gofmt -l .produces no outputgo vet ./...is cleanNew
internal/index/builder_test.go(the package had no tests before) builds a temp module fixture and asserts: struct fields with tags and docs, embedded fields, interface methods with signatures and docs, embedded interfaces, and search-by-struct-tag. Reindexing the live framework confirmsdb-postgres.Confignow exposes all 12 fields with theirEINHERJAR_PG_*tags (andConfig.DSN), andProviderexposesGetExecutor/Begin/BeginTx/Ping/HandleError.Checklist
.gofile (CT-6) — newField/Methodtypes live inindex.gobeside the existingSymbol/Module/etc. type group; consistent with the file's established multi-type schema layoutCHANGELOG.md