chore(release): finalize v0.5.0#70
Conversation
- Bump version 0.5.0-dev -> 0.5.0 across 8 components - Promote CHANGELOG entry from [Unreleased] to [0.5.0] - 2026-04-25 - Refresh uv.lock for the version change Prepares the develop -> main release PR for v0.5.0 (widget production-ready + instructor configuration).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughFinalizes v0.5.0 release: bumps multiple package versions, restructures CHANGELOG to Keep a Changelog, adds changelog governance, introduces new env vars and widget attributes, and extends API/learn/widget documentation and READMEs across the monorepo. Changes
Sequence Diagram(s)(Skipped — changes are primarily documentation, version bumps, and configuration updates.) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request prepares the project for the 0.5.0 release by updating version strings across multiple pyproject.toml files, the lockfile, and the changelog. Feedback was provided to include a new [Unreleased] section in the changelog to ensure future changes can be documented and to maintain the version history in the required order.
- CHANGELOG.md: add empty [Unreleased] block above [0.5.0] with a header comment documenting the convention so contributors and AI agents know where to add entries between releases - CONTRIBUTING.md: new "Changelog" section explaining the during-development vs at-release-time process; add an [Unreleased] entry to the PR checklist Addresses Gemini review on PR #70 (CHANGELOG.md:7).
API reference (docs/reference/api.md):
- New "Learn" section documenting POST /api/v1/learn/query (JSON + SSE,
show_sources flag, document_name) and GET /api/v1/learn/conversations/{id}/turns
(JWT scope, ERR-LEARN-005/006, learn_conversation_turns_read audit row)
- Spell out the show_sources resolution chain in the namespaces PATCH section
- Document the (archived) suffix on document_name for soft-deleted documents
Configuration (docs/reference/configuration.md):
- Add VEKTRA_PROMPT_GROUNDING_MODE (Query pipeline)
- Add VEKTRA_LEARN_SHOW_SOURCES (E-learning)
Error codes (docs/reference/error-codes.md):
- Fix ERR-LEARN-004: 422 -> 409, message corrected to "Duplicate enrollment"
(the documented text never matched the actual handler in vektra-learn/api.py)
Getting started (docs/getting-started/first-query.md):
- Sample response includes document_name; field added to the description table
Component READMEs:
- vektra-learn: full widget integration guide (data-* attrs, sessionStorage
persistence, endpoint table)
- vektra-admin: list namespace config endpoints
- vektra-core: document_name join logic and (archived) fallback
CHANGELOG.md:
- Widget data-* attribute list in v0.5.0 entry was missing
data-powered-by-text and data-powered-by-url (both shipped in PR #66)
Scope: HIGH + MEDIUM drift from the v0.5.0 doc audit. LOW items
(component README polish, dedicated widget guide, helper docs in
vektra-shared README, configuration variable count reconciliation)
deferred to a follow-up.
- vektra-learn/README.md: widget script src corrected to /static/learn/vektra-chat.js (FastAPI mount, vektra-app/main.py:656). The previous /static/vektra-chat.js example would have 404'd for every integrator that copy-pasted it. - docs/reference/api.md, docs/getting-started/first-query.md: note that document_name can be null when the document join returns no row. - docs/reference/api.md: note that turns[].answer is null for an in-flight turn (question recorded before the LLM completes). Found during self-review of the v0.5.0 doc-alignment commit.
.env.example:
- Add VEKTRA_PROMPT_GROUNDING_MODE (Query pipeline section)
- Add VEKTRA_LEARN_SHOW_SOURCES (Learn section)
Both ship in v0.5.0 and were already in configuration.md, but operators
copying .env.example would not have seen them.
vektra-learn/README.md:
- Clarify data-show-sources parsing: only the trimmed lowercase string
"false" hides the citations block; any other value (including "true",
"yes", "0") forces it visible. The previous wording ("force or suppress")
did not capture this asymmetry.
- Clarify data-token-refresh-url: triggered after a 401 (reactive, not
preemptive) via POST with same-origin credentials; expects {"token": ...}.
docs/reference/error-codes.md:
- ERR-LEARN-001 can return 503 (registry not initialized) or 500
(conversation store does not support decryption — VEKTRA_CONVERSATION_KEY
missing). The previous single 503 hid the configuration-error path.
CHANGELOG.md:
- Reconstruct the missing [0.4.0] - 2026-04-11 section. The v0.4.0 git tag
exists but the changelog jumped straight from [0.5.0] to [0.3.0]. Entry
covers FEAT-006/007/009/010/020, BUG-013/014/015/016/017/018,
DEBT-010/011/016, TECH-002, the eval harness, prompt hardening, and the
supply-chain build fix.
Found during the second-round self-review of the doc-alignment work.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/reference/api.md`:
- Line 421: The table row for `sources[].document_name` is not a full sentence;
update its description to be clear, grammatical, and use full sentences. Replace
the fragment with something like: "The filename of the source document. If the
document is soft-deleted, the filename includes an `(archived)` suffix. This
field may be null when the document join returns no row." Ensure you update the
text associated with `sources[].document_name` only.
In `@vektra-learn/README.md`:
- Around line 85-87: The README table entry for the POST
/api/v1/learn/enrollments endpoint currently shows the wrong auth scope; update
the auth column for `/api/v1/learn/enrollments` from "API key (`admin`)" to "API
key (`ingest`)" so it matches the implementation that calls
require_scope("ingest").
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c228bb6b-bc5d-46bf-a046-426b99c16b26
📒 Files selected for processing (9)
.env.exampleCHANGELOG.mddocs/getting-started/first-query.mddocs/reference/api.mddocs/reference/configuration.mddocs/reference/error-codes.mdvektra-admin/README.mdvektra-core/README.mdvektra-learn/README.md
✅ Files skipped from review due to trivial changes (4)
- vektra-core/README.md
- vektra-admin/README.md
- docs/getting-started/first-query.md
- .env.example
- POST /api/v1/learn/enrollments requires ingest scope (the implementation
uses require_scope("ingest")), not admin. Documenting it as admin would
drive integrators to provision the wrong key for the LMS-side flow that
pre-creates students before issuing dashboard tokens.
- POST /api/v1/learn/content/ingest: drop the "/admin" annotation. Admin is
a superscope across the project (vektra-shared/auth.py:require_scope) so
listing it on every row is noise; the column shows the minimum scope.
Addresses CodeRabbit comment 3143276917.
api.md: - Complete the ## Learn section with the four endpoints that were left out of the HIGH+MEDIUM batch: POST /tokens, POST/GET/DELETE /enrollments, POST /content/ingest. Each documents auth scope (admin or ingest), request body, and primary response shape. - Apply CodeRabbit nit on document_name description (3143276914). configuration.md: - Variable count summary now reflects the actual code: 59 Pydantic- validated VEKTRA_* + 1 read directly via os.environ.get (VEKTRA_CORS_ORIGINS, in vektra-app/main.py) + 2 external API keys + 2 infrastructure = 64 total. The previous 55/59 numbers were understated and grew progressively wrong. .env.example: - Add the three missing env vars so operators copying the file see them: VEKTRA_ANALYTICS_STORE_TRACES, VEKTRA_DEBUG_LOG_QUERIES, VEKTRA_LLM_EXTRA_BODY. These have existed since v0.3.0/v0.4.0 but never made it into the example. vektra-shared/README.md: - Replace the one-paragraph stub with a real index of what lives in the package: 9 Protocol interfaces, shared types, config, auth, errors, audit, namespace resolvers (resolve_grounding_mode, resolve_show_sources), ProviderRegistry, startup validation. README.md (root): - Repo structure list was missing vektra-app and vektra-shared. Add both with one-line descriptions; refresh the per-component descriptions for vektra-analytics, vektra-learn, and vektra-admin to reflect the v0.5.0 surface (QueryTrace storage, JWT-scoped API, namespace config endpoints). docs/architecture/index.md: - Components list was missing vektra-analytics and vektra-learn (Phase 2 components, not "Phase 1 plus learn" as the file implied). - ADR table extended to ADR-0023/0024/0025; total decisions count bumped from 60 to 64 to match .s2s/architecture.md. - Startup validation said 8 steps; the actual lifespan runs 11 (analytics_check, learn_check, qdrant_check are the Phase 2 additions). Step descriptions now match the code in vektra-app/main.py:lifespan rather than restating the Phase 1 plan.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/architecture/index.md`:
- Line 82: Update the documentation line describing step 9 to reflect the actual
behavior of the implementation: change the “analytics storage path reachable”
phrasing to state that _step_9_analytics_check only verifies that
AnalyticsService is registered with ProviderRegistry (i.e., a registration
check), not that any storage path is reachable; reference the
_step_9_analytics_check function and the AnalyticsService/ProviderRegistry
symbols when editing the description so it matches the code.
- Line 74: The doc line overstates validation: change the Step 1 wording to
indicate that startup only instantiates VektraSettings (the flat Phase 1
aggregation) and does not perform specialized sub-config validation; note that
sub-configs are validated later by consuming components (see VektraSettings in
vektra_shared.config and the Phase 2 sub-config validators) so update the
sentence to reflect instantiation-only behavior rather than full sub-config
validation.
- Line 83: Update Step 10 wording to describe validation rather than
instantiation: remove any phrase saying "LearnService instantiation" and replace
it with a clear statement that Step 10 validates the presence of a registered
LearnService and enforces JWT secret constraints for "vektra-learn" (actual
instantiation/registration happens during provider registration in Step 5).
Mention the symbols LearnService and vektra-learn so readers understand this
step checks registration and JWT requirements, not creation.
In `@vektra-shared/README.md`:
- Around line 11-17: Update the README signatures for the namespace resolvers to
match the actual implementation: replace the documented
`resolve_grounding_mode(namespace_id, *, defaults)` and
`resolve_show_sources(namespace_id, *, defaults)` with the real function
signatures `resolve_grounding_mode(namespace: str, session_factory: Any,
default_mode: str = "strict") -> str` and `resolve_show_sources(namespace: str,
session_factory: Any, default_value: bool = True) -> bool`; specifically change
the parameter name `namespace_id` to `namespace`, replace the generic `defaults`
param with `session_factory`, and add the explicit `default_mode` /
`default_value` parameters (including their types/defaults) so the README
matches the code in namespace.py.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d95a08c9-2c59-4a5e-9c0a-b2f86d4cdc8b
📒 Files selected for processing (7)
.env.exampleREADME.mddocs/architecture/index.mddocs/reference/api.mddocs/reference/configuration.mdvektra-learn/README.mdvektra-shared/README.md
✅ Files skipped from review due to trivial changes (1)
- README.md
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/reference/api.md
- docs/reference/configuration.md
- .env.example
architecture/index.md:
- Step 1: clarify that startup only instantiates the flat VektraSettings
aggregation; sub-configs are validated independently by their consumers,
not by step 1 (the previous wording overstated what step 1 guarantees).
- Step 5: add analytics_service and learn_service to the provider list
so it is clear that step 9/10 only re-check registrations made here.
- Step 9: replace the "storage path reachable" claim with the actual
behavior: a registry presence check on AnalyticsService. No I/O.
- Step 10: drop "LearnService instantiation" wording. Instantiation
happens in step 5; step 10 verifies the registration is present and
enforces the >=32 char JWT secret constraint.
vektra-shared/README.md:
- Match the actual resolver signatures from namespace.py:
resolve_grounding_mode(namespace: str, session_factory: Any,
default_mode: str = "strict") -> str
resolve_show_sources(namespace: str, session_factory: Any,
default_value: bool = True) -> bool
Note that the caller pre-resolves the env-var fallback into default_*.
- Drop the incorrect claim that vektra-admin uses these resolvers.
Verified callers: vektra-core (per-query, grounding mode only) and
vektra-learn (per-query, both). vektra-admin computes the equivalent
resolved view inline in GET /admin/namespaces/{id}/config so its
response can carry both stored and resolved blocks side-by-side.
Addresses CodeRabbit comments 3143359749 (HIGH), 3143359750 (HIGH),
3143359751 (LOW), 3143359752 (LOW).
vektra-app/README.md:
- Components-wired list was missing vektra-shared, vektra-analytics,
vektra-learn (pre-existed since Phase 2 wired them in but the README
was never refreshed). Step count was 8; the actual lifespan runs 11.
- Mention the static mounts (/static/learn for the chatbot widget,
/admin/static for the admin dashboard) since they are part of the
application assembly this package owns.
docs/README.md:
- Configuration entry said "40 environment variables"; the real surface
is 64 (59 Pydantic-validated + VEKTRA_CORS_ORIGINS via os.environ +
2 external API keys + 2 infrastructure). Number sourced from the
variable count summary in configuration.md.
docs/guides/contributors/index.md:
- Component ownership map was missing vektra-app, vektra-analytics,
and vektra-learn. CODEOWNERS already covers these directories;
the doc was just out of sync.
vektra-ingest/README.md, vektra-index/README.md, vektra-analytics/README.md:
- Stub READMEs (5–7 lines each) that still described the Phase 1
surface only. Refreshed each with the Phase 2 implementations that
ship in v0.5.0:
ingest - Unstructured (OCR, opt-in), dual chunking, sparse
BM25 ingestion path, async lifecycle phases, batch ops
index - Qdrant + SearchMode enum (DENSE/SPARSE/HYBRID),
FastEmbedBM25Provider, raw_filters escape hatch,
atomic reindex
analytics - QueryTrace shape (pipeline / retrieval / generation
fields, eval_mode capture), reporting endpoints,
independent retention via VEKTRA_ANALYTICS_RETENTION_DAYS
docs/architecture/index.md:
- Protocol interface descriptions said "in Phase 1" for several
interfaces whose Phase 2 implementations have shipped (Qdrant,
Unstructured, dual chunking, AdvancedQueryPipeline, Presidio
safeguard, LogEventEmitter / WebhookEventEmitter, FastEmbedBM25).
Each protocol now lists Phase 1 and Phase 2 providers explicitly
rather than restating the Phase 1 plan.
EventEmitter naming inversion (CONTEXT.md, architecture.md, docs/architecture):
- The spec said "Phase 2 (implemented): LogEventEmitter, WebhookEventEmitter
deferred to Phase 3." The actual code in vektra-shared/events.py is the
opposite: NoOpEventEmitter + WebhookEventEmitter ship; LogEventEmitter
was never built. Update ARCH-038 description, the section 8.3 detail,
the trace TD-08 row, the requirements traceability row, and the version
2.0 footer to match what actually shipped (HMAC-SHA256 signed HTTP POST
via VEKTRA_WEBHOOK_URL/SECRET/TIMEOUT) and to record the planning
divergence: LogEventEmitter was scoped but the webhook path subsumed
the use case.
vektra-analytics/README.md:
- Reporting section showed a non-existent "/api/v1/admin/analytics/..."
prefix. Replace with the real router endpoints (router prefix /api/v1):
GET /api/v1/traces, GET /api/v1/traces/{response_id}, GET /api/v1/metrics.
docs/architecture/index.md:
- Protocol 9 (EventEmitter) listed both LogEventEmitter and
WebhookEventEmitter as Phase 2 implementations. Drop LogEventEmitter
for the same reason as above.
vektra-ingest/README.md:
- Clarify that INSTALL_UNSTRUCTURED is a Docker BUILD ARG
(not a runtime env var) so operators don't try to set it in .env.
Also enumerate the actual ElementType values to back the
"10-class element classification" claim.
Found by another verification pass against the current code.
vektra-analytics/README.md:
- Reporting endpoints required admin scope (require_scope("admin"));
the previous wording did not say so.
- /traces filters: list all of them (namespace, from, to, model,
min_duration_ms, limit, offset) instead of a vague "namespace and
time-range".
- /metrics shape: drop the overstated "p50/p95 latency, retrieval/rerank
score distributions, grounding-mode breakdown". The actual
MetricsResponse fields are total_queries, avg_latency_ms,
p95_latency_ms (no p50), avg_retrieval_score (single avg, not a
distribution), queries_per_hour, model_distribution. No rerank
scores and no grounding-mode breakdown live in the metrics response.
- Note 404 ERR-ANALYTICS-002 on missing trace.
vektra-ingest/README.md:
- The async ingest section conflated "status" and "phase" into a
single mixed list and invented an "indexing" phase that does not
exist in the code.
- status (terminal/running): processing, indexed, failed (jobs.py)
- phase (during processing): extracting, chunking, embedding
(the only on_phase calls in pipeline.py)
- Split the two so polling logic is unambiguous: callers look at
status to decide when to stop, and use phase/percentage for UI.
The README claimed startup.py provides the helpers for all 11 ARCH-057
steps, with a step list that didn't match reality:
- It mixed step 5 contents ("conversation store registration" — that
is registered in step 5, not its own step) into the step-9 slot.
- It put "qdrant collection check" at step 10 (it is step 11).
- It listed an "audit table presence" step that does not exist in
vektra-app/main.py:lifespan.
In fact startup.py only owns two helpers — check_database_connectivity
and check_database_schema, used by steps 2 and 3 — plus the
StartupValidationError exception. The other nine steps are inline
in vektra-app/main.py.
Replace the description with the accurate split (which two steps the
package owns vs which nine live in the app), enumerate the actual
nine inline steps, and cross-link to the architecture index for the
canonical full list.
Found by another verification pass; this README's step list and
docs/architecture/index.md were contradicting each other.
Coordinated with vektralabs/vektra-moodle#14. Updates README, docs/README, ROADMAP, GOVERNANCE, CONTRIBUTING h1s and the README "vs Toolkits" comparison table + footer to "Vektra RAG". CHANGELOG entry under [0.5.0] Changed. Repo name, Python package names (vektra_*), Docker images, container names, CLI commands, and internal code identifiers are unchanged (divided decision: brand on user-facing surfaces, stability on technical identifiers).
Two trailing user-facing surfaces missed in the previous branding pass: - .github/ISSUE_TEMPLATE/bug_report.yml description (visible in the GitHub "New issue" picker) - .gemini/styleguide.md h1 (read by Gemini Code Assist when reviewing PRs) Body labels (e.g. "Vektra version:", "Start Vektra with docker compose") remain as short form, consistent with the in-product brevity exception (same logic kept for the widget "Powered by Vektra" link).
Two final v0.5.0 docs/branding alignments before merge: 1. Widget default footer label: "Powered by Vektra" -> "Powered by VektraLabs". The link points to vektralabs.github.io (the org landing) so the maintainer- credit pattern fits the org name better than the residual short form. Updates chat-ui.js source and the vektra-learn/README default-value doc; the bundle under vektra-learn/static/ is rebuilt at Docker build time (gitignored) so no artifact is committed. Custom data-powered-by-text overrides unaffected. 2. New consolidated docs/guides/widget-integration.md (LMS-agnostic). Covers server-side JWT issuance, all 14 data-* attributes, conversation persistence (sessionStorage, 24h TTL), token refresh (data-token-refresh-url and the onTokenExpired callback), source-citation visibility resolution chain, error states, security notes, end-to-end PHP and Python examples, and troubleshooting. Linked from docs/README.md under Guides. Replaces the previous fragmented coverage scattered between vektra-learn/README, API reference, and configuration docs. CHANGELOG entries added under [0.5.0] for both items.
Three real inaccuracies caught in the widget-integration guide review:
1. Auth header: examples used `X-API-Key:` but the API uses
`Authorization: Bearer` (HTTPBearer). Fixed in curl, PHP, and Python
examples.
2. Request body: examples passed only `{"namespace": "<id>"}` but
TokenRequest requires both `student_id` and `course_id` (namespace is
optional, defaulting to course_id). Fixed in all three examples + added
a "required vs optional" note next to the curl block.
3. JSDoc in widget/src/index.js still referenced "Powered by Vektra" as
the default footer text after the rebrand to VektraLabs. Updated for
consistency with the bundle.
No CHANGELOG entry: these correct internal docs already added under
[0.5.0] in the previous commit; the guide ships accurate from day one.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/guides/widget-integration.md`:
- Line 85: The in-page anchor fragments for the Token refresh and Source
citations links are incorrect; update the fragment identifiers used on the
`data-show-sources` line and the other affected link at line 93 to match the
actual section IDs in the document (use the exact heading IDs for "Token
refresh" and "Source citations" as rendered in the markdown) so the links
navigate correctly to those sections; locate the links referencing
`data-show-sources` and the other broken fragment and replace the fragment
portions with the exact, case-sensitive markdown IDs of the target headings.
- Around line 213-225: The example HTML returns an f-string that injects
unescaped values (course_id, token, VEKTRA_HOST) into attributes; update the
FastAPI example to HTML-escape these interpolated values before rendering (e.g.,
call html.escape or markupsafe.escape on VEKTRA_HOST, course_id, and token) so
the string returned by the function uses the escaped variables in the src and
data-* attributes and avoids XSS when copy-pasted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9b45d363-c4fc-4820-b99c-f0ae643b282e
⛔ Files ignored due to path filters (2)
.s2s/CONTEXT.mdis excluded by!.s2s/**.s2s/architecture.mdis excluded by!.s2s/**
📒 Files selected for processing (18)
.gemini/styleguide.md.github/ISSUE_TEMPLATE/bug_report.ymlCHANGELOG.mdCONTRIBUTING.mdGOVERNANCE.mdREADME.mdROADMAP.mddocs/README.mddocs/architecture/index.mddocs/guides/contributors/index.mddocs/guides/widget-integration.mdvektra-analytics/README.mdvektra-app/README.mdvektra-index/README.mdvektra-ingest/README.mdvektra-learn/README.mdvektra-learn/widget/src/chat-ui.jsvektra-shared/README.md
✅ Files skipped from review due to trivial changes (9)
- ROADMAP.md
- .gemini/styleguide.md
- GOVERNANCE.md
- docs/README.md
- .github/ISSUE_TEMPLATE/bug_report.yml
- vektra-app/README.md
- vektra-learn/widget/src/chat-ui.js
- vektra-index/README.md
- README.md
🚧 Files skipped from review as they are similar to previous changes (6)
- CONTRIBUTING.md
- docs/guides/contributors/index.md
- vektra-ingest/README.md
- vektra-learn/README.md
- vektra-analytics/README.md
- vektra-shared/README.md
CodeRabbit comment 3143802562 (HIGH/Major): the FastAPI integration example interpolated course_id, token, and VEKTRA_HOST directly into HTML attributes. As integration guidance shown to readers who will copy-paste it, this had to demonstrate safe escaping explicitly. Added `import html` and pre-escape course_id, token, and VEKTRA_HOST via `html.escape(..., quote=True)` before f-string interpolation. Added a comment explaining why both path-typed and external-source values need escaping. The PHP example was already safe (uses htmlspecialchars()).
CodeRabbit comment 3143802559 (LOW/Minor): two in-page anchor links pointed at fragments that don't match the rendered section IDs. Section headings include the FEAT-XXX suffix in parentheses, so GitHub/Jekyll auto-anchors include it too: - "## Token refresh (FEAT-009)" -> #token-refresh-feat-009 - "## Source citations (FEAT-014)" -> #source-citations-feat-014 Updated the two table rows on lines 85 and 93 to use the correct fragment IDs.
- Adopt Keep a Changelog 1.1.0 with always-on [Unreleased] block - Release v0.5.0 (aligns plugin tag with vektra-stack v0.5.0 / FEAT-014) - Rebrand external surfaces to "Vektra RAG for Moodle"; in-product labels and code identifiers unchanged - Add CONTRIBUTING.md (branch flow, signing, changelog, PR checklist) - Bump version.php: 2026032200 -> 2026042600, release '0.3.0' -> '0.5.0' Reviews: 4/4 addressed (Gemini 4) CI: phpcs --standard=moodle pass on PHP 8.2/8.3/8.4, release zip structure pass Coordinated with: vektralabs/vektra-stack#70 (merged fb987ba)
Summary
Release prep for v0.5.0 ahead of the
develop -> mainPR:0.5.0-dev->0.5.0in all 8 componentpyproject.toml[Unreleased] — v0.5.0to[0.5.0] - 2026-04-25uv.lock(vektra-* version bumps + harmlessupload-timemetadata)Why
Both
developandmainare protected, so the version+CHANGELOG bumpneeds its own PR. Once merged, the
develop -> mainrelease PR can be opened.Test plan
Refs
.s2s/plans/20260418-v050-widget-and-prof-config.mdSummary by CodeRabbit
Chores
Documentation
New Features