feat: retrieve applicable experience by text - #6
Merged
Merged
Conversation
Add ExperienceFinalizationService: one call that loads a completed captured run, evaluates its own closed verification round, checks host authorization and the host's storage decision, reflects, creates the record as Candidate, and commits its initial lifecycle event to Validated or Quarantined. Record, reflection and event IDs derive from the run, so a retry re-derives them and converges instead of duplicating. Required checks can now name the evaluator kind that may satisfy them, and Core and Storage.Postgres each expose a service-registration extension. The MAF adapter finalizes a fully captured run through the host's resolver. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add IExperienceCandidateSource with a PostgreSQL implementation: scope, status and confidence filtering plus a full-text match over a generated tsvector column added by migration 0003. Core's ExperienceRetrievalService applies expiry and environment eligibility, then ranks candidates on relevance, confidence, recency, status and environment compatibility with configurable validated weights, exposing every normalized component and effective weight. Retrieval is bounded by a timeout that returns an empty result with a timeout signal rather than throwing, caller cancellation stays distinct, and a capped candidate pool is reported through Truncated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Story 2.2. Stored records become findable: text-matched, eligibility-filtered and ranked.
IExperienceCandidateSourcein Abstractions, with a PostgreSQL implementation.IExperienceRecordStoreis untouched.0003adds a generatedtsvectorcolumn over task ID, task summary and reflection lesson, with a GIN index. Scope, eligible status and the confidence threshold are applied in the same statement; relevance comes from normalizedts_rank_cd.ValidatedandReinforcedare eligible. Expiry and environment compatibility are decided over the returned candidates, and each exclusion says which check removed it.ExperienceId. A golden fixture pins the documented order.Decisions recorded in the spec
Expiry and required environment attributes were undefined in planning, so this story defines them:
MaxAgeagainstUpdatedAt, and required attributes as key/value pairs where a missing key excludes the record and an empty set marks the result unrestricted. Recency decays by half every 30 days, which keeps the axis defined when no expiry is configured.Review
Three reviewers raised 21 findings, all fixed. The substantive one: ranking only saw the strongest text matches, so a high-confidence recent record with a weaker match could never surface while the docs claimed every eligible record was returned. Truncation is now reported through
Truncatedand the ceiling is documented. Also fixed: the timeout path could exceed its own bound by cancelling Npgsql synchronously on the caller's thread, a token-source leak, unbounded task text and timeouts, and a relevance assertion that could not fail.Test plan
dotnet build --configuration Release: 0 warnings, 0 errorsdotnet test --configuration Release: 523 of 523 pass (Core 307, Postgres 123). Locally withTESTCONTAINERS_RYUK_DISABLED=true.0003applied over an existing hand-migrated database.🤖 Generated with Claude Code