Skip to content

feat(project-graph): activate semantic extraction on import + LLM-grounded extractor (Phases 1–2, folds #927) - #931

Merged
seonghobae merged 6 commits into
developfrom
feat/project-graph-llm-extractor
Jul 11, 2026
Merged

feat(project-graph): activate semantic extraction on import + LLM-grounded extractor (Phases 1–2, folds #927)#931
seonghobae merged 6 commits into
developfrom
feat/project-graph-llm-extractor

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

What (stacked on #927 — Phase 2 of #925)

Upgrades project-graph extraction from the deterministic keyword baseline to an LLM-grounded extractor that cannot fabricate:

  • Hard grounding rule: every extracted object must cite content_segment_uids present in the input segments — objects with unknown/missing/partially-unknown citations are dropped. The model cannot introduce uncited domain claims into the graph.
  • Unknown object_type dropped; confidence clamped to [0,1]; titles bounded to the DB column limit.
  • Prompt-injection hardening: segment text is passed strictly as JSON data (mirrors api/llm.py); base_url goes through the SSRF-validated provider client; request bounded to 40 segments × 2000 chars.
  • Selection knob: PROJECT_GRAPH_EXTRACTOR=keyword|llm (default keyword → zero behavior change). The llm path reuses the import's OpenAI-compatible provider credentials and falls back to keyword on any failure — the projection is never lost to a provider outage.

Verification (local — 7 new tests + 18 regressions green)

grounded mapping + evidence edges · hallucinated/empty citations dropped · unknown type dropped + confidence clamped · empty segments short-circuit (no LLM call) · selection: llm-when-configured / keyword-fallback-on-failure / keyword-default.

Follow-up (Phase 3, per #925)

Corrections → per-tenant eval set + calibrated confidence.

🤖 Generated with Claude Code

seonghobae and others added 2 commits July 6, 2026 09:13
…agged)

Wires the existing-but-dead project semantic graph pipeline into the import
path: after an imported email commits, its content segments are projected into
project_graph_objects via extract_project_semantics + persist_project_graph_
projection. This makes the projects /candidates surface return real data instead
of an empty store.

Safety:
- Gated behind PROJECT_GRAPH_EXTRACTION_ENABLED (default False) -> zero change
  to existing import behavior until explicitly enabled.
- Best-effort: runs AFTER the email is committed, wrapped in try/except with
  rollback, so a projection failure never fails the email import.
- Segments are snapshotted before commit (in-memory, no async lazy-load) to
  avoid MissingGreenlet; persistence runs after commit when segments have ids.
- Workspace scope uses the repository's convention (workspace-<org_id>, or
  workspace-<user_id> without an org).

Tests (tests/test_project_graph_import_wiring.py, 6): real deterministic
extractor + mocked persistence — mapping, workspace scoping (org + user
fallback), no-op on empty/no-objects, and best-effort rollback on failure.
Existing import + project-graph suites unaffected (56 passed).

This is Phase 1 of docs/plans/2026-07-06-ai-moat-project-graph-activation.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RkKdtHRLG4wSLh6PVsp8J
…ations

Phase 2 of the project-graph activation plan (stacked on the Phase 1 import
wiring): upgrades extraction from the deterministic keyword baseline to an
LLM-backed extractor that cannot fabricate.

- services/project_graph/llm_extractor.py: structured-output extraction over
  the imported email's content segments. Hard grounding rule: every object
  must cite content_segment_uids present in the input; objects with unknown,
  missing, or partial-unknown citations are DROPPED. Unknown object types
  dropped; confidence clamped to [0,1]; segment text passed as JSON data
  (prompt-injection hardening, mirrors api/llm.py); base_url goes through the
  SSRF-validated provider client; segments capped (40 x 2000 chars) to bound
  tokens.
- Selection: PROJECT_GRAPH_EXTRACTOR=keyword|llm (default keyword -> zero
  behavior change). The llm path reuses the import's OpenAI-compatible
  provider credentials and falls back to the keyword extractor on any
  failure, so the projection is never lost to a provider outage.

Tests (7): grounded mapping + evidence edges; hallucinated/empty citations
dropped; unknown type dropped + confidence clamped; empty segments short-
circuit without an LLM call; selection uses llm when configured, falls back
to keyword on llm failure, defaults to keyword. Regressions green (18).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RkKdtHRLG4wSLh6PVsp8J
@seonghobae
seonghobae changed the base branch from feat/project-graph-import-activation to develop July 6, 2026 12:47
@seonghobae seonghobae changed the title feat(project-graph): LLM-grounded extractor with enforced segment citations (Phase 2) feat(project-graph): activate semantic extraction on import + LLM-grounded extractor (Phases 1–2, folds #927) Jul 6, 2026
@seonghobae
seonghobae enabled auto-merge July 6, 2026 23:46
Comment thread backend/tests/test_project_graph_import_wiring.py Fixed
Comment thread backend/tests/test_project_graph_llm_extractor.py Fixed
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR governance metadata gate is not ready for 29c3ca09ee50eadb28b40ec477c374b13de7cbda:

@opencode-agent
opencode-agent Bot disabled auto-merge July 11, 2026 11:09
@opencode-agent

opencode-agent Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: c050fa0672c49e5a3c91f2d6f5a8cfef1cb8353a
  • Workflow run: 29163313061
  • Workflow attempt: 1
  • Gate result: APPROVE (approval step)

Pull request overview

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including backend/core/config.py, backend/services/email_import_service.py, backend/services/project_graph/llm_extractor.py, backend/tests/test_project_graph_import_wiring.py, backend/tests/test_project_graph_llm_extractor.py.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects backend/core/config.py to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source checks are delegated to configured OpenCode web_search/Context7/DeepWiki sources when applicable; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: Playwright visual, DOM locator, ARIA snapshot, console, and responsive evidence were checked when a web UI surface was present; for non-web surfaces, API/CLI/log/docs/workflow interaction evidence was reviewed instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

  • Result: APPROVE
  • Reason: No blocking issues found; changes are well-tested and documented.
  • Head SHA: c050fa0672c49e5a3c91f2d6f5a8cfef1cb8353a
  • Workflow run: 29163313061
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Backend (5 files)"]
  S1 --> I1["API and service runtime"]
  I1 --> R1["Review risk: Backend (5 files)"]
  R1 --> V1["backend tests"]
Loading

@opencode-agent opencode-agent Bot 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

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including backend/core/config.py, backend/core/env_paths.py, backend/scripts/private_mail_http_smoke.py, backend/scripts/start_backend.py, backend/services/email_import_service.py, and 5 more.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects backend/core/config.py to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source checks are delegated to configured OpenCode web_search/Context7/DeepWiki sources when applicable; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: Playwright visual, DOM locator, ARIA snapshot, console, and responsive evidence were checked when a web UI surface was present; for non-web surfaces, API/CLI/log/docs/workflow interaction evidence was reviewed instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

  • Result: APPROVE
  • Reason: All checks passed, no unresolved threads, and implementation completeness verified.
  • Head SHA: 29c3ca09ee50eadb28b40ec477c374b13de7cbda
  • Workflow run: 29150489511
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Backend (10 files)"]
  S1 --> I1["API and service runtime"]
  I1 --> R1["Review risk: Backend (10 files)"]
  R1 --> V1["backend tests"]
Loading

@seonghobae
seonghobae enabled auto-merge July 11, 2026 11:19
@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head verification for 29c3ca09ee50eadb28b40ec477c374b13de7cbda:

  • GitHub Checks: all current-head checks are green. This includes Application CI, CodeQL, Dependency Review, Bandit, Trivy, Security Scan (dependency-review, trivy-fs, osv-scan, scorecard), Strix, Docker image validation, PR Governance, and OpenCode Review.
  • Code scanning: refs/pull/931/head has 0 alerts.
  • Review threads: all current review threads are resolved. The two github-code-quality comments about mixed import styles were fixed in backend/tests/test_project_graph_import_wiring.py and backend/tests/test_project_graph_llm_extractor.py.
  • Local verification before push: py -3 -m pytest backend\tests passed (1271 passed, 29 skipped); focused project-graph tests passed; ruff passed on changed files.
  • Failure log reason made explicit: the failed PR Governance / metadata-only gate evaluation run 29150489507 reported 1 unresolved current review thread(s) remain while review-thread state was still stale. After GraphQL showed both threads resolved, the failed job was rerun and passed at 2026-07-11T11:13:35Z.
  • OpenCode Review approved the current head in run 29150489511; result: APPROVE, no blocking findings.

Auto-merge has been enabled. Direct merge remains blocked by branch protection review policy (REVIEW_REQUIRED, additional approval/last-push approval), so I am not bypassing policy with an admin merge.

@opencode-agent opencode-agent Bot 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

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including backend/core/config.py, backend/services/email_import_service.py, backend/services/project_graph/llm_extractor.py, backend/tests/test_project_graph_import_wiring.py, backend/tests/test_project_graph_llm_extractor.py.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects backend/core/config.py to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source checks are delegated to configured OpenCode web_search/Context7/DeepWiki sources when applicable; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: Playwright visual, DOM locator, ARIA snapshot, console, and responsive evidence were checked when a web UI surface was present; for non-web surfaces, API/CLI/log/docs/workflow interaction evidence was reviewed instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

  • Result: APPROVE
  • Reason: No blocking issues found; changes are well-tested and documented.
  • Head SHA: c050fa0672c49e5a3c91f2d6f5a8cfef1cb8353a
  • Workflow run: 29163313061
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Backend (5 files)"]
  S1 --> I1["API and service runtime"]
  I1 --> R1["Review risk: Backend (5 files)"]
  R1 --> V1["backend tests"]
Loading

@seonghobae
seonghobae merged commit e87a681 into develop Jul 11, 2026
40 checks passed
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