Skip to content

feat(finder): make the publisher host free-text searchable - #94

Merged
kperry-godaddy merged 2 commits into
mainfrom
feat/finder-publisher-fts
Jul 23, 2026
Merged

feat(finder): make the publisher host free-text searchable#94
kperry-godaddy merged 2 commits into
mainfrom
feat/finder-publisher-fts

Conversation

@kperry-godaddy

@kperry-godaddy kperry-godaddy commented Jul 23, 2026

Copy link
Copy Markdown
Member

What

Adds the publisher host (the URN <publisher> segment — the agent's verified domain) as a searchable column in the Finder's FTS5 index, so free-text queries match host words: "translator" now finds translator.example.com even when the display fields share no tokens with the host.

  • Migration 002_fts_publisher.sql — FTS5 has no ALTER TABLE, so the FTS table is dropped, recreated with the publisher column, and repopulated from the base + side tables (group_concat … ORDER BY rowid). Self-contained: no feed replay needed. ACTIVE rows only, so tombstoned agents are not resurrected — pinned by tests on both the migration path and the runtime tombstone path.
  • insertFTS threads the same publisher value the base-row insert derives, so base and FTS columns agree by construction.
  • Migration observabilityOpen records applied migrations (Store.AppliedMigrations) and ans-finder logs them at startup, so the first in-place schema upgrade a deployed DB performs is diagnosable from logs alone.
  • Spec: text-matching contract — documents exact-token AND matching, case/diacritic-insensitivity, no stemming/prefix expansion, phrase semantics for dotted terms (translator.comtranslator.example.com), FTS-operators-as-literals, and ranking as informational. The Query.text description, its example (flight booking — the old find me a flight booking agent cannot match under all-terms-must-match), the score normalization note, and the explore description are aligned with it. Both spec copies synced (make docs-sync; byte-equality test enforces).
  • register.sh — demo display text derived from the host (presentation polish; searchability comes from the publisher column), truncated to the RA's 64/150-char field limits so long-but-legal DNS labels still register.

Upgrade & rollback notes

  • Fresh databases apply 001+002 together; deployed 001 databases upgrade in place, transactionally, at startup — watch for the new applied index migrations log line.
  • Rolling the binary back past 002 and forward again leaves agents registered during the window without publisher tokens until their next renewal (old binary writes 5-column FTS rows; 002 doesn't re-run). Remedy if needed: delete the finder DB and replay the feed (existing runbook step 3).

Review

Six-perspective review (security, architect, skeptic, systems, go, api): 0 critical, 0 high findings. Consensus MEDIUM/LOW items fixed in this PR: phrase-vs-AND semantics documented correctly (empirically verified against modernc.org/sqlite v1.54.0), spec self-contradiction on Query.text resolved, bm25 softened to informational, migration logging added, group_concat ordering pinned, register.sh length overflow fixed, tags repopulation now tested with data. Deferred (noted, not blocking): centralizing URN parsing in internal/ard, per-column bm25 weights, maxLength on query.text (pre-existing surface).

Verification

  • make buildgo vetmake lint: 0 issues ✅
  • go test ./...: all packages pass; race detector clean ✅
  • make test-cover: 90.7% ≥ 90% gate ✅
  • Upgrade path tested against the shipped 001 schema read from the embedded FS (cannot drift), including the revoked-row non-resurrection case ✅

DCO

Signed off by the submitter per CONTRIBUTING.md; the DCO certification is the human submitter's, made at their direction.

AI assistance

Assisted-by: Claude Code (claude-fable-5)

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the agent’s publisher host (verified domain / URN <publisher> segment) to the Finder’s FTS5 index so free-text queries can match host tokens (e.g., translatortranslator.example.com), and documents the Finder’s exact text-matching semantics in the OpenAPI spec(s).

Changes:

  • Rebuilds the Finder FTS5 virtual table to include a publisher column and repopulates it from existing ACTIVE rows via a new SQLite migration.
  • Threads the derived publisher value through the runtime FTS insert path and adds tests covering host-token matching and tombstone suppression.
  • Documents the Finder’s text-matching contract in both spec copies and improves scripts/demo/register.sh display/description text derived from host (with length truncation).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
spec/api-spec-finder-v1.yaml Documents the Finder text-matching contract and clarifies query.text/score semantics.
internal/adapter/docsui/openapi/finder.yaml Syncs the same spec changes for the docs UI copy.
internal/adapter/store/sqlitefinder/migrations/002_fts_publisher.sql Drops/recreates the FTS table to add publisher and repopulates it from base/side tables for ACTIVE rows only.
internal/adapter/store/sqlitefinder/apply.go Adds publisher threading so runtime inserts keep base and FTS publisher values consistent.
internal/adapter/store/sqlitefinder/sqlite.go Tracks and exposes applied migrations so startup can log in-place schema upgrades.
cmd/ans-finder/main.go Logs applied index migrations at startup for operational observability.
internal/adapter/store/sqlitefinder/search_publisher_test.go Adds tests ensuring host tokens are searchable and tombstones remove host discoverability.
internal/adapter/store/sqlitefinder/migrate_internal_test.go Tests upgrade behavior from schema 001 → 002 including repopulation and non-resurrection of revoked rows.
scripts/demo/register.sh Derives display name/description from host and truncates to RA field limits.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// database, in application order. Empty means the schema was already
// current. Callers log this at startup so schema upgrades are
// diagnosable from logs alone.
func (s *Store) AppliedMigrations() []string { return s.appliedMigrations }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3e7454eAppliedMigrations now returns slices.Clone(...).

Free-text search previously covered displayName, description,
capabilities, and tags — but not the one text every entry reliably
carries, the publisher host. A quickstart user who registered
translator.example.com and searched "translator" got zero results
unless the display fields happened to repeat the word.

Add publisher as a fifth FTS5 column. FTS5 has no ALTER TABLE, so
migration 002 drops and recreates the table and repopulates it from the
base and side tables — self-contained, no feed replay, ACTIVE rows only
so tombstoned agents are not resurrected. insertFTS threads the same
publisher value the base-row insert derives, so the two columns agree
by construction. Open now records applied migrations and ans-finder
logs them at startup, making the first in-place schema upgrade
diagnosable from logs alone.

Document the text-matching contract in the finder spec (exact-token
AND, case/diacritic-insensitive, dotted terms match as phrases, FTS
operators are literal, ranking informational) and align the Query.text
description, its example, and the score description with it. register.sh
now derives demo display text from the host — presentation, not a
search requirement — truncated to the RA's field limits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: kperry <kperry@godaddy.com>
@kperry-godaddy
kperry-godaddy force-pushed the feat/finder-publisher-fts branch from 867cfa7 to 2373f9a Compare July 23, 2026 18:32
Returning the internal slice let a caller's sort or in-place append
reach the store's own record. slices.Clone removes the sharing; the
getter runs once at startup, so the copy costs nothing.

Addresses Copilot review feedback on #94.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: kperry <kperry@godaddy.com>
@kperry-godaddy
kperry-godaddy added this pull request to the merge queue Jul 23, 2026
Merged via the queue into main with commit d8ed4bb Jul 23, 2026
3 checks passed
@kperry-godaddy
kperry-godaddy deleted the feat/finder-publisher-fts branch July 23, 2026 19:06
@github-project-automation github-project-automation Bot moved this from Triage to Done in Agent Name Service Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants