Replace the single inline org.assertj.core.api.Assertions.assertThat call
with the static import already used for assertThatThrownBy, per code style
(test sources sync to the open-source repo).
* feat(kb-open): P0-B 9 open API endpoints
Implements the 9 read-only KB Open API endpoints on top of the P0-A
auth skeleton (#441). Each returns an explicit DTO (A5: never raw
entities) and delegates assembly to service-layer methods that return
pure DTOs (A6: no HTTP coupling, MCP-ready).
Endpoints:
- GET /pages/{slug} entity card (mode=summary/full/section:{heading})
- POST /search hybrid retrieval (granularity=entity/chunk)
- POST /search/chunks chunk-level semantic search
- POST /pages/{slug}/traverse entity relation graph (depth ≤ 2)
- GET /pages/{slug}/trace provenance (page → chunk → raw)
- GET /taxonomy pageType/entityType/relationType enumeration
- GET /whats-new recent changes + stale pages
- GET /stats KB statistics
- GET /pages lightweight page list
Components:
- KbOpenApiController: 9 endpoints, each @RequireKbScope annotated
- KbOpenApiService: assembly layer (card, traverse BFS, metadata parsing)
- KbOpenApiDtos: all response DTOs as records (PageCard, TraceResult,
TaxonomyResult, KbStats, WhatsNewResult, TraverseResult, PageList)
Traverse (pragmatic version):
- depth ≤ 2 with explosion guard, predicate LIKE matching
- slug → pageId → mention → primaryEntity (salience-highest)
- neighbor nodes echo slug when available (R11)
- edge sourceHandle via evidenceChunkId → citing page
Tests (4 new, all green):
- KbOpenApiControllerTest: 404 on missing page/slug, delegation to service
Closes#442
* fix(kb-open): address review feedback on #445
BLOCKERS:
- stats.pagesWithLinks always returned 0 because listByKbId() nulls out
content. Switch to listByKbIdWithContent() so [[wiki link]] detection works.
- Test file: replace inline java.util.List.of() FQN with import + simple name
(sync-opensource would expose the unidiomatic style).
NITS (inherited from P0-A rebase):
- V162→V164, prefix VARCHAR(12), FQN imports, parseScopes trim, ?token=
fallback removal, design doc moved to rfcs/ — all now in ancestor commit
6fd62440.
EXTRA:
- whatsNew staleReason: hardcoded Chinese "上游 fact 页面变更" → English
"Upstream fact page changed" (external-facing API response).
* chore(wiki): drop RFC-012 prefix from progress field Javadocs (#449 nit)
Per #449 review (4825113234): the internal RFC-012 reference should not
appear in code. progressPhase/progressTotal/progressDone Javadocs still
carried the "RFC-012 M2 v2 UI:" prefix after #449's English translation
pass — drop it now that these lines are touched.
Zero behavior change.
* chore(kb-open): drop inline FQN in parseScopes (#444 nit)
Per #444 review (4825157096): parseScopes used
`.collect(java.util.stream.Collectors.toUnmodifiableSet())` while
`Collectors` is already imported at the top of the file. Use the simple
name. Zero behavior change.