Skip to content

feat: add multi-language owner evidence bundle - #17

Merged
sting8k merged 26 commits into
mainfrom
feat/owner-evidence-bundle
Aug 12, 2026
Merged

sting8k merged 26 commits into
mainfrom
feat/owner-evidence-bundle

Conversation

@sting8k

@sting8k sting8k commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • add owner attribution and qualified identity evidence for Python, Rust, JavaScript/TypeScript, Java, Kotlin, C#, and PHP
  • add deterministic owner replay/integration coverage and honest Go call-appendix gating
  • compact repeated search evidence, improve confirmed-target/show routing, and advise on low-signal text terms
  • align README, agent guide, changelog, and implementation behavior

Evidence boundary

  • owner evidence is structural navigation evidence, not runtime binding or dispatch proof
  • this PR does not tag, publish, or finalize release metadata

Local verification

  • cargo fmt --check
  • cargo clippy -- -D warnings
  • cargo test --locked — 1,215 passed, 1 ignored
  • node npm/install.test.js
  • (cd npm && npm pack --dry-run)

CI gate

The repository PR workflow runs the Rust gate on both Ubuntu and Windows, plus npm installer/package checks on Ubuntu and Windows with Node 14 and 20. Windows CI is the remaining platform gate for this branch.

sting8k added 24 commits August 11, 2026 11:10
Discover's Confirmed structural targets footer now points to
`srcwalk show <path> --section <symbol>` (bare or Q.N) instead of a
numeric range, so models read the parser-backed symbol body rather than
guessing/reusing numeric ranges that cause partial-function loops.

The --section reader resolves receiver/container-qualified Q.N selectors,
matching US-064 discover semantics. US-064 primitives (split_dot_symbol_query,
normalize_receiver_type, normalize_outline_container, outline_container_kind)
moved to a shared src/lang/qualified.rs used by both search and read, plus a
shared outline resolver with exact dotted-name precedence and Go
receiver-from-signature extraction. A round-trip check gates the symbol footer:
it is emitted only when the selector resolves back to exactly the target range,
otherwise a numeric fallback is retained.
For confirmed structural targets, promote the strongest body address to the
single primary action instead of letting numeric ranges compete:
- Stable symbol-backed targets (wide or narrow) emit the symbol command as the
  primary `> Next:`; the numeric range stays visible as a plain, non-action
  `  evidence anchor: <path>:<start>` metadata line (START line only, never a
  full body range and never a `>`-shaped action hint).
- Ambiguous / non-round-tripping selectors keep the numeric command as the
  primary `> Next:` and are labeled once at block level with a fallback note.
- Header teaches the classification (run printed Next; symbol when stable,
  numeric as fallback) instead of implying every target is symbolic.
- The trailing generic "read the confirmed structural target above" guidance is
  suppressed whenever a confirmed-target block exists, so it cannot compete as
  a second primary action; numeric exact-hit guidance is preserved for
  non-structural text/access/name-occurrence searches.
- Non-structural text/access/partial-completion hints stay numeric unchanged.

Carries the parser-backed selector/round-trip from US-065 through ContextTarget;
no symbol identity inferred from rendered strings. Preserves US-060b bounded
wide evidence, US-063 dedupe/suppression, line caps, and shell quoting.
Add multilanguage owner region extraction (US-067 phase 1). Python
files are parsed into Named owner regions and AnonymousBarriers; a hit
line is attributed to the unique narrowest named owner, abstaining on
equal-width ties, anonymous callables (lambda, unnamed class), decorator
lines, and local parser ERROR/missing-node points.

A version-pinned manifest gate pins the tree-sitter-python NODE_TYPES
fingerprint and verifies callable/container inventories are disjoint, so
grammar drift fails the test suite.

The Go mechanical-call appendix is now gated on an explicit successful
Go parse (go_call_analysis_attempted) plus actual Go owner evidence; the
zero-edge sentence additionally requires a Go-only result with >=2
distinct Go owners. A non-Go honesty caveat is emitted only when non-Go
owner evidence actually rendered. Malformed Go no longer suppresses
nothing nor spuriously renders Go-only claims.

quality matrix: independent-fixture Case table (each parsed separately,
1-based local line numbers, exact qualified_name/start/end per positive
row). 69 positive + 23 intentional abstention assertions, programmatic
>=60 / >=20 floors. Counted abstentions are intentional cases (decorator
lines, class/module outside-callable lines, lambda placement/nesting,
malformed/ERROR/missing hierarchies); blank/separator lines are asserted
incidentally and never count toward the floor.
Corrects the false slice-1 'clippy clean' verification claim: the earlier
grep pattern missed clippy's indented error lines, so python.rs baseline
lints went unreported. Mechanical-only fixes, no behavior change:
- digit separators in FNV-1a fingerprint/hash constants
- u64::from(b) instead of a u8-as-u64 cast
- if-let instead of single-binding match (class_definition)
- method pointer OwnerAnchor::qualified_name
- inline {e:?} format args
- doc_markdown backticks

cargo clippy --lib -- -D warnings exits 0; python owner suite 13 pass.
…ase 2)

Implement the Rust owner adapter pairing exact named forms with honest
barriers/abstentions, satisfying the Rust owner quality matrix and manifest
gate.

Named forms (exact, no guessing):
- Top-level & body-bearing function_item -> name
- Nested module/function -> a::b::f
- Inherent impl -> Type::method (Stack<T>::push)
- Trait default -> Trait::method (Greet::bye)
- Trait impl -> exactly <Type as Trait>::method (<Foo as Display>::fmt)

Malformed-container recovery (structural, not grammar-string patch):
- A collapsed mod/impl/trait with no valid identity is detected via its
  ERROR-recovery context: an expression_statement wrapping a block with an
  immediately-preceding ERROR sibling. Under this `recovery` context every
  contained callable is classified as an AnonymousBarrier (never a guessed
  partial name) while traversal continues, so EVERY callable node is
  classified (omission is a contract violation).
- Valid lexically nested function items inside clean if/loop/match/standalone
  blocks have no ERROR sibling and stay eligible (outer::inner).
- Unreadable/missing impl identity, nameless mod/trait, and nameless function
  all barrier and keep recursing so nested callables are individually
  classified.

Barriers/abstentions: every closure barriers; body-less function_signature_item
abstains; macro_definition barriers; macro_invocation not guessed.

Tests: clean nested-block positives; exhaustive-barrier classification for
malformed mod/impl/trait; manifest gate pinned (0x50a2_cce6_3015_8590); matrix
floor 71/32; cross-language Go edge filter regression preserved.
JS/JSX/MJS/CJS files now carry structural owner attribution via a
tree-sitter-javascript adapter, owner-only (no call edges in phase 3B).

- Dot-joined qualified names (outer.inner, A.foo, A.#priv).
- Direct simple-variable binding wins over an explicit internal name.
- Class fields/methods/get-set/static/private map to Class.name.
- Safety barriers (never omission, never guessed): object-literal
  callables, anonymous classes/IIFEs, member/prototype assignments,
  computed names, class_static_block.
- Named IIFEs use their own name; anonymous -> barrier.
- Manifest gate pins NODE_TYPES fingerprint; quality matrix requires
  >=30 positive + >=10 intentional abstentions.
- Non-Go honesty caveat; no Go mechanical-call appendix.
Generalize the shared JS adapter at the language seam: grammar selected by
detected Lang::{JavaScript,TypeScript,Tsx}, OwnerAnchor.language set to the
actual language. Preserves all JS/JSX behavior and tests. TS/TSX wired into
the same owner-only pipeline (no call edges).

- Body-less callable declarations barrier over exact spans: abstract_method_
  signature, method_signature, function_signature, call_signature,
  construct_signature. Concrete overload impl stays Named on its body node.
- Type-only non-callables transparent (no barrier/no name): property_signature,
  index_signature, function_type, constructor_type.
- Valid .-prefix containers: named/abstract class and TypeScript namespace/
  internal_module/module (readable identifier/nested-identifier segments only;
  string/computed module names sticky barrier).
- public_field_definition is the TS class-field binding node (simple/private
  direct value => A.x; computed/unreadable/anonymous-class sticky barrier).
- ambient_declaration, decorators, export/default, interfaces, type-alias,
  enums are transparent wrappers/traversal containers, never name prefixes.
- Invalid naming context sticky + local ERROR policy identical to JS.

Anti-drift: separate TypeScript and TSX NODE_TYPES inventories + pinned
fingerprints (JS kept separate); every TS executable/body-less callable kind
has exactly one deliberate disposition with fixture coverage.

Tests: combined family matrix >=60 exact positive (name,start,end) checks and
>=20 intentional abstentions; TS fixtures for namespace nesting, abstract+
concrete methods, overload signatures + impl, ambient function, call/
construct/method signatures, transparent function/constructor types inside an
owner, public fields, computed/destructured stickiness, local ERROR, and all
TS callable kinds. CLI integration for real .ts and .tsx; .mts/.cts routing
smoke via existing Lang mapping.
Kotlin owner-only adapter on pinned tree-sitter-kotlin-ng 1.1.0:
- named owners: top-level/class/nested/local functions, named object,
  companion (default 'Companion' or declared name), extension receiver
  prefix, secondary constructor, property accessors, local function path.
- identity barriers for lambda_literal/annotated_lambda/anonymous_function,
  anonymous_initializer, object_literal; abstain bodyless fn/ctor and
  primary_constructor.
- receiver must be a type kind (fixes generic fun <T> receiver bug).
- manifest gate + node-types fingerprint; 60+/20+ quality gate.
- fold Java crossing-context initializer follow-up tests.
- wire Kotlin owner-only seam in owner_links.
Body-bearing function_definition (declared name), method_declaration under
class/interface/trait/enum containers (Service::load), namespace as a `\`
lexical container (Acme\Api\load, Acme\Api\Service::load; braced and unbraced
forms produce the same identity), and body-bearing single-property hooks
(Container::$prop::get/set). Anonymous barriers for anonymous_function,
arrow_function, and anonymous_class; a named function nested inside a callable
body is an identity barrier (PHP registers it globally; neither outer::inner
nor outer.inner); body-less methods/hooks abstain; fail-closed field_nonempty
rejects empty structural names; a namespace name field present-but-empty is a
malformed barrier while a missing field is a valid global namespace.

Curated matrix: 62 positives >=60, 41 abstentions >=20, exact names/ranges.
Version-pinned callable manifest (tree-sitter-php 0.24.2 php grammar) with
PHP_NODE_TYPES fingerprint 0x1297dd3f8fd2f5d3.

Path-isolated: only src/evidence/owners/php.rs.
Add C# owner adapter with fail-closed identity handling:
- Named owners under type+namespace containers, property/event/indexer
  accessors, expression-bodied members, local functions, operators,
  constructors/destructors, conversion operators.
- AnonymousBarrier for lambdas/anonymous methods.
- Trim + non-empty normalization for every required identity component
  (method, local fn, ctor/dtor, operator symbol, conversion target,
  property/event base, namespace/type, accessor kind) so no dangling
  segments like `Service.` / `.get` / `operator `.
- Missing-name namespace/type/accessor and malformed file-scoped
  namespace fail closed (full-range barrier + anonymous descend).

28 tests incl. crossing-context, malformed-identity, and required_identity
normalization regression cases.
@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds structural owner attribution across seven languages, qualified identity evidence, and bounded Go mechanical-call navigation for text-OR discovery.

  • Adds language-specific owner extraction and shared owner-link evidence.
  • Integrates owner rollups, compact search rendering, and low-signal term guidance.
  • Improves qualified symbol targeting and show --section routing.
  • Adds deterministic integration coverage and updates user documentation and package metadata.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/evidence/owner_links.rs Builds shared owner attribution and carefully bounded Go mechanical-call evidence with deterministic ordering and explicit caveats.
src/evidence/owners/mod.rs Provides common narrowest-owner selection and abstention behavior for the new language adapters.
src/commands/find.rs Integrates owner rollups, call appendices, compact text-OR rendering, and low-signal advisories into discovery output.
src/lang/qualified.rs Centralizes qualified selector resolution used by both confirmed-target emission and section reads.
src/read/section.rs Routes symbol-addressed section reads through the shared qualified selector resolver.
src/search/low_signal.rs Adds thresholded guidance for broadly distributed low-signal text queries.
tests/us065_symbol_section_footer.rs Covers symbol-selector round trips, ambiguity fallback, quoting, and qualified identities across supported constructs.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Q[Text OR query] --> S[Search and paginate matches]
    S --> O[Extract structural owners]
    O --> R[Render owner rollups]
    O --> G{Go owners present?}
    G -->|Yes| C[Build bounded mechanical-call appendix]
    G -->|No| N[Render non-Go ownership caveat]
    R --> P[Bounded discovery packet]
    C --> P
    N --> P
Loading

Reviews (3): Last reviewed commit: "chore(release): prepare 1.6.0" | Re-trigger Greptile

@sting8k
sting8k merged commit a6dadfb into main Aug 12, 2026
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.

1 participant