Skip to content

fix(ci): add Postgres service container to backend job, close fresh-install migration gap - #1502

Draft
seonghobae wants to merge 9 commits into
codex/stacked-pr-workflow-triggersfrom
claude/ci-postgres-service-container
Draft

fix(ci): add Postgres service container to backend job, close fresh-install migration gap#1502
seonghobae wants to merge 9 commits into
codex/stacked-pr-workflow-triggersfrom
claude/ci-postgres-service-container

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Current repair finding — 2026-09-05

Exact head 0b9e324a91fd2148b2b2759cca875ac7d50c86a0. Restored to Draft because the already-stamped database finding still requires owner integration; this is not a queued-check blocker or a closure.

A disposable PostgreSQL 16.15 + pgvector run of the current tree completed fresh and repeat Alembic upgrade to 0017_merge_newsdom_carddav_heads and 64 focused tests. This is supplemented-local evidence, not clean-lock, forward-repair, hosted-check, or release proof. The forward repair already belongs to #1503, now 19d5860bc27e860acba940390f5792721cd99e5e on #1565, with exact-lock fresh/repeat migrations and 75 strict tests verified locally. Integrate that ancestry; do not copy another 0019 migration.

Keep this PR's unique pinned CI PostgreSQL service/configuration/governance delta and its workflow prerequisite #1562#1502. #1562 is itself on #1531; its live head must be refreshed before restacking. The historical #1502-before-#1503 proposal is superseded by #1565#1503, so do not introduce a dependency cycle. Fresh current-head review, checks, and immutable protected integration remain required.

Historical description and receipts

Older readiness or source-head statements below are historical where inconsistent with the current repair finding.

Description

The backend job in .github/workflows/app-ci.yml had no services: block, so every @pytest.mark.postgres real-Postgres test connected to nothing and always silently pytest.skip'd — every run, since this pattern was introduced. This was surfaced by running the suite for real against local PostgreSQL 16 + pgvector for the first time in a recent session (recorded as a follow-up in ContextualWisdomLab/.github's docs/product-technical-gap-baseline.md, 2026-09-01 entry, and in naruon#1486's in-progress CHANGELOG entry).

Adds a pgvector/pgvector:pg16 service container (test/test/test_db, pg_isready healthcheck) with a matching DATABASE_URL, which happens to match tests/conftest.py's existing default exactly.

Running the suite for real against local PostgreSQL 16 + pgvector surfaced two latent bugs beyond the CI wiring itself, both of which #1503 also independently hit and fixed while investigating the same real-Postgres failures:

  1. 0011_email_read_state still hardcoded the pre-rename legacy emails table, so alembic upgrade head against a genuinely fresh database crashed with relation "emails" does not exist. #1503's fix is more complete (guards on column existence, not just table existence, and handles both email_records/legacy emails) — adopted verbatim here (byte-identical, verified via git diff against its branch) so the two PRs don't carry conflicting historical-migration semantics.
  2. Raw SQL INSERT INTO email_records in test_bootstrap_db.py and test_data_api.py omitted is_read (Python-side ORM default only, no DB server default), so real Postgres rejected them with NotNullViolationError. Both PRs independently reached the identical fix (verified byte-identical).

Scope note (2026-09-02): per an owner overlap-audit request, this PR was narrowed from an earlier, broader diff down to just this dependency-root CI-enablement slice. PR-governance/stacked-PR-trigger content that had accumulated here was extracted to #1531. Full narrowing rationale: #1502 (comment)

Also updates CLAUDE.md and AGENTS.md so agents know this is now a hard CI gate (not best-effort), and closes the follow-up tracked in ContextualWisdomLab/.github's docs/product-technical-gap-baseline.md.

Fixes: none (CI infrastructure gap-closure + latent bugs it surfaced, not a product feature).

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • This change requires a documentation update

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation (CLAUDE.md, AGENTS.md, CHANGELOG.md)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective (existing raw-SQL seeding tests now exercise the fixed paths for real; migration guard verified by #1503's independent real-Postgres run, adopted here byte-identical)
  • New and existing unit tests pass locally with my changes: full backend suite 1837 passed / 2 skipped (unrelated LIVE_BASE_URL live-API smoke) against real PostgreSQL 16 + pgvector, ruff check . clean, alembic upgrade head and scripts/bootstrap_db.py both idempotent against a fresh database. (This sandbox's own Docker daemon is unavailable for a fresh re-run post-narrowing; substituted py_compile/ruff/isolated-assertion verification — see the narrowing comment linked above for exact commands.)
  • Any dependent changes have been merged and published in downstream modules — n/a, no dependent changes

Generated by Claude Code

…nstall migration gap

backend job in app-ci.yml had no `services:` block, so every
@pytest.mark.postgres real-Postgres test connected to nothing and always
silently pytest.skip'd — nobody knew this ecosystem-wide until it was run
for real. Adds a pgvector/pgvector:pg16 service (test/test/test_db,
pg_isready healthcheck) with a matching DATABASE_URL, matching
tests/conftest.py's existing default.

Running the suite for real against local PostgreSQL 16 + pgvector surfaced
3 more latent bugs beyond the CI wiring itself:

- 0011_email_read_state still hardcoded the pre-rename legacy `emails`
  table (`op.add_column("emails", "is_read", ...)`), so `alembic upgrade
  head` against a genuinely fresh database crashed with
  `relation "emails" does not exist` even after bootstrap_db.py's existing
  legacy-index statement was guarded. email_records (the current ORM
  table) already has is_read, so a fresh install needs this migration to
  be a no-op; guarded it the same way, behind
  sa.inspect(...).has_table("emails").
- Raw SQL INSERT INTO email_records in test_bootstrap_db.py and
  test_data_api.py omitted is_read (Python-side ORM default only, no DB
  server default), so real Postgres rejected them with
  NotNullViolationError. Filled it in explicitly at all 4 call sites.
- test_bootstrap_db.py's local _execute_schema_backfill test helper
  duplicated the old unguarded backfill loop instead of using the new
  scripts.bootstrap_db.execute_schema_backfill; pointed it at the real
  guarded function instead.

Verified against real PostgreSQL 16 + pgvector: full backend suite 1837
passed / 2 skipped (unrelated LIVE_BASE_URL live-API smoke), ruff clean,
`alembic upgrade head` and scripts/bootstrap_db.py both idempotent against
a fresh database. Documented the new hard CI gate in CLAUDE.md and
AGENTS.md so it isn't assumed best-effort going forward.

Closes the follow-up tracked in ContextualWisdomLab/.github's
docs/product-technical-gap-baseline.md (2026-09-01 entry).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: e86434c7-a4f8-4191-9591-1d74f3d9c96a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head audit found and fixed one migration symmetry defect in 1fb88d05fd3d55fa93a4355ce954df242461c1c5: a fresh install skips 0011_email_read_state.upgrade() because the legacy emails table is absent, but its downgrade previously attempted an unconditional DROP COLUMN on that absent table. The downgrade now uses the same table-existence guard. Focused evidence: PYTHONWARNINGS=error uv run --project backend --frozen pytest -q backend/tests/test_alembic_migrations.py → 21 passed; Ruff passed for both changed files; git diff --check passed. The PR remains draft pending fresh current-head hosted checks and substantive current-head robot review.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Correction to the preceding audit note: the exact pushed SHA is 1fb88d051f4c5d95f18ea059f17006bed890f052.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

PR governance metadata gate is not ready for c6ed2e6f9d4f8667d9003bdd2df1085f8a3f9aa5:

  • Required check strix is CANCELLED on the current head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

PR governance metadata gate is not ready라고 띄우는 Workflow가 무슨 소용이 있지? 이슈가 있으면 이슈가 있다고 알리고, GitHub Checks가 실패했으면 실패를 고치기 위한 OpenCode Agent를 contextual-orchestrator 를 orchestrator/free 로 대동해서 띄우는 게 더 생산적이지 않을까?

@seonghobae

Copy link
Copy Markdown
Contributor Author

PR governance metadata gate is not ready라고 띄우는 Workflow가 무슨 소용이 있지? 이슈가 있으면 이슈가 있다고 알리고, GitHub Checks가 실패했으면 실패를 고치기 위한 OpenCode Agent를 contextual-orchestrator 를 orchestrator/free 로 대동해서 띄우는 게 더 생산적이지 않을까? 그리고 OpenCode Agent는 Ready for Review로 넘겨주든 어쩌든 의사결정을 하고.

Copy link
Copy Markdown
Contributor Author

이 PR에서 뜬 건 정확히는 문제 보고가 아니라 의도한 상태입니다 — real Postgres로 검증하는 동안 머지 자동화가 개입하지 않도록 일부러 draft로 열어뒀고, scripts/ci/pr_governance_gate.sh는 그걸 정확히 그대로 알려준 것뿐입니다(add_blocker 'Draft PR: merge automation is paused.', 261행). Ready로 바꾸면 이 blocker는 저절로 사라집니다 — 지금은 CI 큐가 밀려 아직 결과를 못 받아서 draft로 남겨둔 상태입니다.

더 넓은 질문(왜 announce만 하고 contextual-orchestrator/orchestrator-free로 OpenCode Agent를 띄워 직접 고치지 않는가)에 대해서는, 코드를 읽어보면 이 워크플로 자체가 CHECK_NAME='metadata-only gate evaluation'로 명시된 순수 read-only/결정론적 상태 체크입니다 — draft·BEHIND·DIRTY·CHANGES_REQUESTED·미해결 리뷰 스레드·필수 체크 누락·CodeRabbit blocking 여부를 GitHub API로 확인해 코멘트 하나로 보고할 뿐, 코드는 건드리지 않습니다. CLAUDE.md의 governance 모델("OpenCode judges PRs; GitHub Actions performs mechanical updates and merges")과 일치하는 의도적 분리로 보입니다 — 이 게이트는 push·comment·review 등 PR 이벤트마다 org 전체에서 도는데, 그때마다 LLM agent를 기동하면 대부분(지금 이 경우처럼 실제로는 결함이 없는 draft 상태)은 낭비입니다. 실제 자동 수정 경로는 이미 별도로 존재합니다 — pr-review-autofix.ymlcontextual_orchestrator_review_sidecar.sh(orchestrator/free)가 approved 상태 PR의 base-merge/conflict 해결만 좁게 담당합니다.

이 gate가 잡는 다른 blocker(CHANGES_REQUESTED, 미해결 스레드, CodeRabbit blocking finding 등)까지 autofix 범위를 넓히고 싶으시면, 그건 naruon이 아니라 ContextualWisdomLab/.github의 중앙 워크플로 설계 변경이라 이 PR 범위 밖입니다 — 원하시면 별도로 다뤄보겠습니다.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

추가하신 "OpenCode Agent가 Ready for Review 전환까지 의사결정" 부분은 제 답변이 놓쳤네요 — 그 부분만 짚습니다.

이 PR 한정으로는 이미 그렇게 되고 있습니다: 이 PR을 연 게 저(이 세션)이고, CI가 실제로 통과하는지 계속 지켜보다가 확인되면 제가 직접 ready로 바꿀 겁니다 — 그 판단을 하는 agent가 이미 붙어 있는 셈입니다, 별도로 하나 더 띄울 필요 없이.

owner께서 그리시는 건 아마 더 일반적인 경우 — PR을 연 세션이 다시 돌아오지 않고 draft로 방치되는 경우, org 차원에서 그런 draft들을 지켜보다가 체크가 다 통과하면 자동으로 ready로 승격하는 별도 상시 agent — 인 것 같은데, 맞다면 이것도 naruon이 아니라 ContextualWisdomLab/.github의 중앙 워크플로에 새 컴포넌트를 추가하는 설계라 이 PR 범위 밖입니다. 원하시면 그 설계를 별도 이슈/PR로 다뤄보겠습니다.


Generated by Claude Code

@seonghobae

Copy link
Copy Markdown
Contributor Author

근데 왜 동작 안 해?

Copy link
Copy Markdown
Contributor Author

확인해봤습니다 — 이건 이 PR의 문제가 아니라 org 전체의 Actions 러너 용량 고갈로 보입니다.

즉 org 차원에서 동시에 굉장히 많은 자율 세션이 PR을 계속 push하고 있고, 그 총 동시 요청량이 GitHub Actions 동시 실행 한도를 넘어서 있는 것으로 보입니다. 제 쪽에서 이 PR 안에서 고칠 수 있는 문제가 아니라, org/계정의 Actions concurrency 한도(플랜 상향 또는 self-hosted runner 추가)나, 동시에 push되는 세션 수를 줄이는 쪽에서 다뤄야 할 것 같습니다. 이 PR은 큐가 풀릴 때까지 계속 지켜보고 있겠습니다.


Generated by Claude Code

@seonghobae

Copy link
Copy Markdown
Contributor Author

Fresh PostgreSQL runtime evidence for current HEAD 1fb88d051f4c5d95f18ea059f17006bed890f052: started an isolated pgvector/pgvector:pg16 database using the CI credentials, then ran PYTHONWARNINGS=error uv run --frozen alembic upgrade 0011_email_read_state. Alembic advanced from an empty database through 0011_email_read_state; PostgreSQL confirmed emails absent and email_records present. Next, uv run --frozen alembic downgrade 0009_project_graph_projection completed successfully and alembic current reported 0009_project_graph_projection (branchpoint), again with emails absent and email_records present. The temporary database container was removed afterward. No repository changes were produced. The PR remains draft pending current-head hosted gates and substantive independent review.

seonghobae and others added 2 commits September 1, 2026 12:03
… change

11377dd removed the develop/master/release/** branch restriction from
app-ci.yml's and docker-publish.yml's pull_request: triggers (so governed
checks run on stacked PRs too), but left two test_release_governance.py
assertions pinned to the old branch-restricted shape
(`assert "release/**" in workflow`, `assert "develop" in
pull_request_block`) — genuine RED, reproduced locally. Updated both to
assert the new intended shape (no branches: restriction on the
pull_request trigger), matching tests/test_stacked_pr_workflow_contract.py.

Verified: full backend suite 1838 passed/2 skipped against real Postgres,
ruff clean, scripts/ci/test_pr_governance_gate.sh PASS,
tests/test_stacked_pr_workflow_contract.py passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH
@seonghobae
seonghobae marked this pull request as ready for review September 1, 2026 03:36
devin-ai-integration[bot]

This comment was marked as resolved.

seonghobae pushed a commit that referenced this pull request Sep 1, 2026
PR #1502 (opened in parallel, ~5 minutes before this one) independently
diagnosed the same underlying gap from the same root cause -- running the
real backend suite against actual PostgreSQL for the first time -- and found
something this PR didn't: app-ci.yml's backend job has never had a Postgres
services: container, so every @pytest.mark.postgres test (including all the
new ones in this PR) has always silently skipped in real CI. It ships the
authoritative fix for that, plus its own version of the 0011_email_read_state
/bootstrap_db.py fix, with a pinned contract test.

Landing two different versions of the same files from two open PRs would
conflict. Adopt #1502's exact pattern for the overlapping files instead of
this PR's earlier approach:

- 0011_email_read_state.py: has_table("emails")-guarded no-op, keeping the
  original "emails" target, rather than retargeting to "email_records".
  (0011_email_model_reconciliation's own docstring clarifies no migration
  ever renamed "emails" to "email_records" for a real managed database --
  email_records was the actual table name since inception; "emails" was
  only ever a stale copy-pasted string. Both approaches are safe in
  practice, so there's no reason to diverge from the already-tested pattern.)
- bootstrap_db.py / 0001_initial_control_plane.py: schema_backfill_sql()'s
  callers now go through execute_schema_backfill(), which skips the legacy
  ix_emails_owner_date statement via identity-matching a LEGACY_EMAILS_INDEX
  sentinel rather than this PR's simpler unconditional deletion.
- test_alembic_migrations.py: contract test now asserts
  execute_schema_backfill, plus #1502's own
  test_email_read_state_legacy_table_guard_is_reversible pinning the
  reconciled 0011 file's shape.
- test_bootstrap_db.py / test_data_api.py: the 4 raw SQL
  `INSERT INTO email_records` smoke-seeding call sites now set is_read
  explicitly (Python-side ORM default only, no DB server default, so real
  Postgres rejects the omission) -- the exact bug flagged as a follow-up
  earlier in this PR's own investigation.

Re-verified end-to-end: fresh-database migration to head, and the true
historical-database reproduction (migrate to 0015, drop the workspace
registry tables, continue to head crossing both 0011_email_read_state and
0016_document_org_scope) both still complete cleanly. Full backend suite:
1841 passed, 0 failed, 3 skipped (up from 1838/2 failed -- the last 2
pre-existing failures are now fixed too), ruff clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ErwZSYW3pm585NiM3Q7aN
seonghobae pushed a commit that referenced this pull request Sep 1, 2026
Devin Review found two real gaps in the has_table("emails")-only pattern
adopted from PR #1502 in the previous commit:

1. A genuinely historical database -- one whose own 0001 ran before
   is_read was added to the Email model, so it has email_records without
   is_read -- silently never gets the column: has_table("emails") is False
   (per 0011_email_model_reconciliation's docstring, no managed database
   ever really had a table literally named "emails"), so upgrade() returned
   without touching email_records at all. Reproduced directly: migrated to
   0009, dropped email_records.is_read to simulate that historical state,
   continued to head with the has_table("emails")-only version -- it
   completed with no error, but is_read was permanently missing. Confirmed
   the same reproduction now correctly adds is_read to email_records.

2. Not idempotent: a legacy "emails" table that already has is_read (e.g.
   from a partial/earlier application) made upgrade() crash with a
   duplicate-column error, since it only checked has_table before calling
   op.add_column. Reproduced directly (manually created an "emails" table
   with is_read already present, migrated to head) and confirmed it no
   longer crashes.

Now checks both "email_records" (the table that actually matters) and
"emails" (defensive, in case a real one somehow exists), guarded by column
existence via the same _has_column helper this repo's other migrations
already use, so upgrade/downgrade are safely idempotent either way.

This diverges from PR #1502's exact pinned file shape (its
test_email_read_state_legacy_table_guard_is_reversible asserted the
has_table-only version byte-for-byte), so updated this PR's own contract
test to check for the corrected shape instead of matching that exact text.
Worth flagging on #1502 too, since the same gaps apply to its own version
of this file if it hasn't already been fixed there.

Full backend suite: 1841 passed, 0 failed, 3 skipped, ruff clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ErwZSYW3pm585NiM3Q7aN
@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head governance audit confirmed the CodeRabbit issue comment was an approval-pending notice, not a finding: it says there are no unresolved comments and that the latest commit has not yet been reviewed. The prior parser matched the phrase “blocking issues” inside CodeRabbit’s hypothetical approval sentence and falsely published a blocker. Current head 154cff09c4090fc5af0a5f8626679e49f9b83cb5 now recognizes that marked notice as a wait state while preserving real blocking-comment detection. All 3 review threads were already resolved and informational. Regression evidence: bash scripts/ci/test_pr_governance_gate.sh PASS; git diff --check PASS.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Correction: the exact pushed current-head SHA is 154cff09718f7a0f1d4e45223b149f4176210597.

devin-ai-integration[bot]

This comment was marked as resolved.

…ing CodeRabbit notice

Devin Review flagged a real regression in 154cff0: once a CodeRabbit
approval-pending issue comment routes to add_waiting, it does so
unconditionally — even when CODERABBIT_COUNT was 0 and the documented
no-check-run fallback (a structured, exact-current-head OpenCode
adversarial approval) had already been accepted. That fallback exists
specifically so governance isn't stuck when CodeRabbit itself is what's
unavailable; a CodeRabbit issue comment saying it hasn't reviewed yet is
exactly that unavailability, not a new blocker.

Tracks whether the fallback was accepted (OPENCODE_FALLBACK_APPROVED) and
skips the approval-pending wait when it was. Added
missing_coderabbit_adversarial_approval_with_pending_notice, combining a
valid OpenCode fallback approval with a pending CodeRabbit notice, and
asserting governance completes (conclusion=success) rather than waiting.

Verified the fixed conditional directly against all 4
(OPENCODE_FALLBACK_APPROVED, CODERABBIT_APPROVAL_PENDING_COUNT) input
combinations — only the previously-broken combination changes outcome,
from "waiting" to "ready", matching intent. Could not execute
scripts/ci/test_pr_governance_gate.sh itself in this sandbox pass (a
persistent tool restriction on that specific script, unrelated to the
change); the new scenario mocks and assertion follow the file's existing
patterns exactly. Please re-run the harness locally to confirm.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH

Copy link
Copy Markdown
Contributor Author

Devin Review's finding on scripts/ci/pr_governance_gate.sh lines 470-471 was real: once a CodeRabbit approval-pending issue comment routed to add_waiting, it did so unconditionally — even when CODERABBIT_COUNT was 0 and the documented no-check-run fallback (an accepted, exact-current-head OpenCode adversarial approval) had already been satisfied. That fallback exists precisely so governance isn't stuck when CodeRabbit itself is unavailable; an approval-pending notice saying CodeRabbit hasn't reviewed yet is exactly that unavailability.

Fixed in 40ce573b: tracks whether the fallback was accepted (OPENCODE_FALLBACK_APPROVED) and skips the wait when it was. Added missing_coderabbit_adversarial_approval_with_pending_notice, combining a valid OpenCode fallback approval with a pending CodeRabbit notice, asserting governance completes (conclusion=success) rather than waiting — per Devin's suggested prompt.

One caveat: I could not execute scripts/ci/test_pr_governance_gate.sh itself in this sandbox pass — a persistent tool restriction specific to that script (even a no-op bash -n syntax check was refused), unrelated to the change itself. I verified the fixed conditional directly against all 4 input combinations of (OPENCODE_FALLBACK_APPROVED, CODERABBIT_APPROVAL_PENDING_COUNT) — only the previously-broken combination changes outcome, from "waiting" to "ready", matching intent — and the new mock/assertion follow the file's existing patterns exactly. Since you've been running this harness successfully locally, could you confirm it passes there?


Generated by Claude Code

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor Author

Two items in the latest gate comment, neither needs another push:

"Current-head CodeRabbit issue comment has blocking warning/failure evidence" — this is the same approval-pending CodeRabbit comment as before, and it's a false positive for a specific, expected reason: .github/workflows/pr-governance.yml triggers on pull_request_target, which runs the base branch's (develop's) trusted copy of scripts/ci/pr_governance_gate.sh, not this PR's. Since this PR's fix to that exact script hasn't merged to develop yet, the gate evaluating this PR is still running the old, unfixed version against itself — a PR that edits the trusted governance script can't have its own fix apply to itself before merge. That's the documented trust boundary, not a regression. Once this merges, the fix applies to every PR afterward, including retroactively correct evaluation of future events on this one.

"Required check strix is CANCELLED" — consistent with the same Actions-queue exhaustion from earlier (still 0 in_progress runs repo-wide as of this check); most likely cancelled by concurrency/timeout pressure rather than anything in this diff.

Nothing left to fix in the diff itself — still waiting on the queue to clear so real checks can run, and/or the branch-ruleset bypass.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Fresh overlap audit against #1503 shows this current branch is no longer a single bounded CI slice. #1502 still owns a unique, useful root capability — provisioning real pgvector/pgvector:pg16 for the backend CI job so @pytest.mark.postgres tests stop soft-skipping — but its current diff also carries migration/bootstrap/read-state repairs that #1503 has since evolved further, plus separate stacked-PR/governance workflow changes.

The overlap is semantic, not title-only: both branches modify the historical email migration/bootstrap path and real-Postgres evidence, while #1503 now also carries the forward 0019_email_read_state_repair needed for databases already stamped past 0011 and the workspace registry/document migration work. Keeping both implementations independently mergeable risks conflicting historical-migration semantics and duplicated tests.

Please converge this external lane without rewriting another active branch: retain #1502 as the dependency-root CI-enablement slice only (Postgres service + the minimum executable contract/docs proving real-Postgres tests run), and move/drop any migration behavior already owned and more completely covered by #1503. The unrelated PR-governance/stack-trigger behavior should remain in its own existing owner lane rather than hitchhike on the Postgres service PR. After narrowing, regenerate exact-head CI/security/review evidence. Then #1503 can be restacked on the fresh #1502 head or protected develop after #1502 merges, preserving only its unique workspace/migration repair delta. Do not transfer predecessor checks/reviews/approvals.

Copy link
Copy Markdown
Contributor Author

Fresh post-extraction check: #1531 now exists at 38a53eead795460bcfa696219bfa6d7286813f06, but #1502 current head 40ce573bfa695ff433a086ef748244a11afc6c71 still contains the extracted governance changes in its own diff: .github/workflows/app-ci.yml still removes the PR-base filter as well as adding Postgres, and bandit.yml, dependency-review.yml, docker-publish.yml, scripts/ci/pr_governance_gate.sh plus the stacked-PR/governance tests remain present. That means the split has been created but the original lane has not yet converged, so the same governance behavior is currently duplicated across open PRs.

Please finish the split on this existing external branch: remove from #1502 every governance/stack-trigger delta now owned by #1531 and preserve only the real-Postgres CI enablement plus the minimum causally required executable migration/test/docs changes that are not supplied by its product/data successor. Then re-diff against #1503: any historical 0011/bootstrap behavior that #1503 already supersedes with the forward 0019_email_read_state_repair and workspace-registry migration should not remain as a second competing migration authority unless the exact clean-install dependency requires it and the two branches have an explicit tested ordering. Regenerate exact-head CI/security/review evidence after narrowing; predecessor results do not transfer.

…on fix with #1503

Owner's request on this PR (2026-09-02): this branch had accumulated
unrelated content over a long, CI-congestion-heavy session. Narrows it
back to its stated purpose -- the dependency-root CI-enablement slice
(Postgres service container + the minimum fix needed to make the newly
real-executing tests pass) -- and converges the overlapping migration fix
with #1503's independently-derived, more complete implementation so the
two branches don't carry conflicting historical-migration semantics.

Moved out entirely (zero diff vs develop now), extracted to
#1531:
- .github/workflows/{bandit,dependency-review,docker-publish}.yml and
  app-ci.yml's `pull_request: branches:` removal (stacked-PR base support)
- tests/test_stacked_pr_workflow_contract.py
- backend/tests/test_release_governance.py's stacked-PR assertions
- scripts/ci/pr_governance_gate.sh + scripts/ci/test_pr_governance_gate.sh
  (CodeRabbit approval-pending + OpenCode fallback governance-gate fixes)

Converged with #1503 (adopted its exact implementation, verified
byte-identical via diff against its branch):
- backend/alembic/versions/0011_email_read_state.py: #1503 independently
  found and fixed the same relation "emails" does not exist crash, more
  completely -- guards on column existence (not just table existence) and
  checks both "email_records" and legacy "emails", vs. this branch's
  simpler has_table-only guard. Adopting it here means #1503's later
  rebase onto this PR (once merged) is a clean no-op on this file instead
  of a conflict between two divergent fixes for the same bug.
- backend/scripts/bootstrap_db.py: same convergence for
  execute_schema_backfill's legacy-index handling.
- backend/tests/test_alembic_migrations.py: swapped this branch's
  test_email_read_state_legacy_table_guard_is_reversible (asserted the
  old implementation's exact shape) for #1503's
  test_email_read_state_guards_both_legacy_and_current_table_names,
  which asserts the now-shared implementation instead.

backend/alembic/versions/0001_initial_control_plane.py,
backend/tests/test_bootstrap_db.py, and backend/tests/test_data_api.py
needed no changes -- diffed identically against #1503's branch already
(both PRs independently reached the exact same is_read raw-SQL fix and
0001 refactor while investigating the same real-Postgres failures).

Net result: 10 files changed vs. develop (down from 18), matching the
"dependency-root CI-enablement slice" scope the owner asked for.

Verification (real-Postgres re-run blocked by this sandbox having no
usable Docker daemon -- ExpressJS-style hashes/lint/isolated-assertion
checks substitute; the point of this very PR is to make GitHub's own CI
runners do the authoritative check):
- python3 -m py_compile on every touched Python file: clean.
- python3 -m ruff check on every touched backend file: all checks passed.
- backend/tests/test_alembic_migrations.py's three targeted test
  functions executed directly (bypassing this sandbox's unrelated
  conftest.py/cryptography import breakage): all 3 pass.
- git diff against develop for every "moved out" file: zero lines,
  confirming a clean revert.
- git diff against #1503's branch for the converged migration/bootstrap
  files: zero lines, confirming byte-identical adoption.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH

Copy link
Copy Markdown
Contributor Author

Narrowed per the request above. New exact head c6ed2e6f, diff now 10 files changed vs. develop (down from 18):

Moved out entirely (zero diff vs develop now) to a new PR, #1531:

  • .github/workflows/{bandit,dependency-review,docker-publish}.yml and app-ci.yml's pull_request: branches: removal — the stacked-PR base support (your own commits)
  • tests/test_stacked_pr_workflow_contract.py
  • backend/tests/test_release_governance.py's stacked-PR assertions
  • scripts/ci/pr_governance_gate.sh + scripts/ci/test_pr_governance_gate.sh — the CodeRabbit approval-pending + OpenCode fallback governance-gate fixes

Converged with #1503 (verified byte-identical via git diff against its branch, zero lines):

  • backend/alembic/versions/0011_email_read_state.py#1503 independently found and fixed the same relation "emails" does not exist crash, more completely (column-existence guard, both email_records/legacy emails). Adopted its exact implementation here so #1503's later restack onto this PR is a clean no-op on this file rather than a conflict between two fixes for the same bug.
  • backend/scripts/bootstrap_db.py — same convergence.
  • backend/tests/test_alembic_migrations.py — swapped my narrower test for #1503's test_email_read_state_guards_both_legacy_and_current_table_names, which asserts the now-shared implementation.

backend/alembic/versions/0001_initial_control_plane.py, backend/tests/test_bootstrap_db.py, and backend/tests/test_data_api.py needed no changes — they already diffed identically against #1503's branch (both PRs independently reached the exact same is_read raw-SQL fix and 0001 refactor while investigating the same real-Postgres failures).

Verification: this sandbox has no usable Docker daemon (dockerd won't start — permission-restricted), so I couldn't re-run the real-Postgres suite here; that's exactly what this PR's own CI now does. Substituted: python3 -m py_compile on every touched file (clean), ruff check on every touched backend file (all checks passed), the 3 targeted test_alembic_migrations.py functions executed directly and passing (isolated from this sandbox's own unrelated conftest/cryptography import breakage), and git diff confirming both the clean reverts and the byte-identical convergence with #1503.

Once this merges to develop, #1503 should be able to restack with its 0001/0011/bootstrap_db.py/test_alembic_migrations.py/test_bootstrap_db.py/test_data_api.py deltas collapsing to nothing, keeping only its unique workspace-registry/document-migration work.

Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

This is already done as of my previous comment (issuecomment-5503879697), which landed just before this one — head is now c6ed2e6f, not 40ce573b. app-ci.yml no longer touches the PR-base filter (services/DATABASE_URL only), and bandit.yml/dependency-review.yml/docker-publish.yml/scripts/ci/pr_governance_gate.sh/scripts/ci/test_pr_governance_gate.sh/tests/test_stacked_pr_workflow_contract.py all diff at zero lines against develop now (verified via git diff). The 0011_email_read_state.py/bootstrap_db.py convergence with #1503 (adopting its exact, more-complete implementation rather than keeping a second competing migration authority) is also done — see that comment for the full breakdown.

Separately: your and Devin's review on #1531 caught a real bug in the extracted governance-gate logic itself (OpenCode's fallback approval could clear a genuinely-pending CodeRabbit lane) — fixed there, not here: #1531 (comment)

Claude-Session: https://claude.ai/code/session_019YgmaEKnPhrsbSyQBierFH


Generated by Claude Code

@seonghobae seonghobae added bug Something isn't working priority: high High-priority or P1 work status: needs-review Open pull request requiring current-head review or checks type: bug Defect or incorrect behavior labels Sep 2, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Contributor Author

noema-review finally ran (after ~9 hours queued in the org-wide CI backlog) and failed on the current head c6ed2e6f, but not because of anything in this PR's diff:

Noema LLM response was not valid JSON (Expecting ',' delimiter: line 1 column 4722)
repair failure: Noema reviewed line entry 3/3 cites path='backend/alembic/versions/0011_email_read_state.py' line=12 side='RIGHT', which is not an exact changed-side line

The reviewing model hallucinated a line number that isn't among this file's actual changed lines (nearest real changed lines: 7-11, +47 more elsewhere in the diff) — the fail-closed gate (ContextualWisdomLab/.github#1671's repair-diagnosability fix) correctly rejected the fabricated citation rather than accept it. This is the same orchestrator/free free-tier-model-reliability pattern already tracked in ContextualWisdomLab/.github's docs/product-technical-gap-baseline.md, not a defect in this migration file. Triggered the one re-run this protocol calls for (rerun_failed_jobs on run 33587140022) — a different model in the pool may produce a valid citation.


Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

The re-run I triggered earlier on run 33587140022 (previous comment) has now completed — failed again, same class of problem, different specifics:

Noema bounded repair transport was exhausted; initial failure: Noema LLM response was not valid JSON
(Expecting ',' delimiter: line 1 column 4822); repair failure: NoemaRepairDeadlineExceeded: Noema repair
exceeded 900-second absolute wall-clock deadline

Same signature just showed up on naruon#1531 independently (different PR, different diff, same orchestrator/free-pool JSON-malformation → repair-timeout chain) — confirms this is systemic in the shared model pool/repair path, not specific to this PR's migration file. Since this was already the one permitted re-run for this failure chain, not retrying a third time. Nothing left to fix in this PR's own diff; a real fix belongs in contextual-orchestrator's free-tier model catalog/repair reliability, outside this PR's and this repo's scope. Continuing to watch for the queue/central-review infra to stabilize.


Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Fresh exact-head RCA on c6ed2e6f9d4f8667d9003bdd2df1085f8a3f9aa5 separates product evidence from the required-review control plane.

Repository-local Application CI, SAST Semgrep, Dependency Review, Bandit, Security Scan, and Docker validation are terminal-success on this head. The required noema-review check/job 100251945105 nevertheless failed after runner acquisition, repository-scoped reviewer authentication, exact-head validation, contextual-orchestrator sidecar health, provider-route preflight, and orchestrator/free gateway preflight all succeeded. Its terminal error was malformed model JSON followed by the historical caller-owned NoemaRepairDeadlineExceeded 900-second repair deadline. No Naruon source finding was established and raw model output was correctly withheld from public logs.

That run used trusted central workflow source .github@9330d41c92b1e6ab35261f3f5189936ea1ad8bff. The canonical owner has since merged .github#1672; current protected .github/main removes the duplicate repository-side repair call and the unsupported 900-second caller deadline. Fresh consumer evidence and the request to revalidate this unchanged head against current central truth are recorded on .github#1637.

Do not churn this Naruon branch merely to retrigger the historical Noema implementation. This PR remains non-mergeable in the governance sense: coverage-evidence is still queued, the failed Noema evidence is non-passing until current-owner revalidation occurs, and the latest REST review inventory contains COMMENTED history only rather than a qualifying independent approval on this exact head.

@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 could not approve from deterministic current-head evidence because GitHub Checks have failed.

Findings

1. HIGH Current-head GitHub Checks - Fix failed required checks before approval

  • Problem: Failed same-head checks remain for c6ed2e6f9d4f8667d9003bdd2df1085f8a3f9aa5.
  • Root cause: The model-unavailable evidence fallback is allowed only when peer GitHub Checks are complete and clean.
  • Fix: Read and fix the failed check logs below, then rerun the current-head checks.
  • Regression test: Keep the model-unavailable fallback gated on an empty failed-check rollup.

Failed checks:

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Workflow: app-ci.yml"]
  S1 --> I1["GitHub Actions review job"]
  I1 --> R1["Review risk: Workflow: app-ci.yml"]
  R1 --> V1["actionlint plus required checks"]
  Evidence --> S2["Repository file: AGENTS.md"]
  S2 --> I2["repository behavior"]
  I2 --> R2["Review risk: Repository file: AGENTS.md"]
  R2 --> V2["required checks"]
  Evidence --> S3["Repository file: CHANGELOG.md"]
  S3 --> I3["repository behavior"]
  I3 --> R3["Review risk: Repository file: CHANGELOG.md"]
  R3 --> V3["required checks"]
  Evidence --> S4["Repository file: CLAUDE.md"]
  S4 --> I4["repository behavior"]
  I4 --> R4["Review risk: Repository file: CLAUDE.md"]
  R4 --> V4["required checks"]
  Evidence --> S5["Backend: 0001_initial_control_plane.py (3 files)"]
  S5 --> I5["API and service runtime"]
  I5 --> R5["Review risk: Backend: 0001_initial_control_plane.py (3 files)"]
  R5 --> V5["backend tests"]
  Evidence --> S6["Test: test_alembic_migrations.py (3 files)"]
  S6 --> I6["regression suite"]
  I6 --> R6["Review risk: Test: test_alembic_migrations.py (3 files)"]
  R6 --> V6["targeted test run"]
Loading

@opencode-agent

opencode-agent Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

Bind the pgvector CI service to the verified multi-architecture digest and keep the pin covered by release-governance tests.

Signed-off-by: Seongho Bae <me@seonghobae.me>
@seonghobae
seonghobae changed the base branch from develop to codex/stacked-pr-workflow-triggers September 4, 2026 16:43
@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head restack repair:

The failed frontend job 101014032311 did not reach product tests. Its exact failure was Corepack resolving mutable https://registry.npmjs.org/pnpm/latest, followed by read ECONNRESET. #1562 owns the shared workflow correction and installs repository-pinned pnpm@11.5.3 before setup-node requests pnpm cache metadata.

This PR now inherits that prerequisite through an ordinary non-force merge and targets the prerequisite branch. Its effective eleven-file database/bootstrap delta is unchanged. actionlint passed for the inherited workflows; 40 release-governance/stacked-workflow tests and 62 focused migration/bootstrap/data tests passed, with two PostgreSQL-dependent tests explicitly skipped in the local no-service run. Fresh hosted checks and independent current-head review remain required; predecessor check/review evidence does not transfer.

@seonghobae
seonghobae marked this pull request as draft September 4, 2026 23:30
@seonghobae
seonghobae marked this pull request as ready for review September 5, 2026 05:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b9e324a91

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +27 to +31
inspector = sa.inspect(op.get_bind())
for table_name in _CANDIDATE_TABLES:
if inspector.has_table(table_name) and not _has_column(
inspector, table_name, "is_read"
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add a new revision for already-stamped databases

For any installation whose Alembic history already includes 0011_email_read_state—for example, a database bootstrapped and then stamped before adopting the managed migration path—command.upgrade(..., "head") will never execute this edited upgrade() again, so email_records.is_read remains absent and ORM reads or inserts can still fail. Keep this guard for fresh installs if needed, but also ship the guarded email_records addition in a new revision descending from the current head and verify upgrading a schema already stamped past 0011.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T05:30:29.061810Z 0b9e324 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

seonghobae added a commit that referenced this pull request Sep 5, 2026
Non-force merge of PR #1565 into migration owner #1503. Exact synchronization exposed the undeclared TestClient dependency previously masked by an extra local package. Preserve both complete deltas and use #1565 as the direct prerequisite, superseding the historical #1502-before-#1503 proposal without closing either lane.

Verified merged tree 793aadd with fresh and repeat Alembic upgrade to 0019_email_read_state_repair, 75 strict PostgreSQL/dependency tests, Ruff, and diff checks. Consumer propagation and hosted gates remain unverified.

Co-Authored-By: Codex <noreply@openai.com>
Signed-off-by: Seongho Bae <me@seonghobae.me>
@seonghobae
seonghobae marked this pull request as draft September 5, 2026 07:01
@seonghobae seonghobae removed the status: needs-review Open pull request requiring current-head review or checks label Sep 6, 2026
@seonghobae seonghobae added the status: draft Draft pull request label Sep 6, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: high High-priority or P1 work status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants