Co-authored-by: Molecule AI Core-DevOps <core-devops@agents.moleculesai.app>
Co-committed-by: Molecule AI Core-DevOps <core-devops@agents.moleculesai.app>
tier:low and tier:high are OR gates — any one positive verdict
is sufficient. The previous implementation required ALL groups to have
positive verdicts, causing INCOMPLETE even when core-devops APPROVED
and core-lead was absent.
Now uses tier-specific logic:
- tier:low / tier:high (OR): any positive = CLEAR
- tier:medium (AND): all positive = CLEAR
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Paginate all list endpoints (comments, reviews) to handle PRs with
many comments without missing entries. Uses per_page=100 with page
increment loop, safety-capped at 20 pages.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Gitea reviews use "submitted_at" not "created_at" for when the review
was submitted. The earlier signal_1_comment_scan fix (inherited from
sop-tier-check investigation) already handled this; signal_2 and
signal_3 were missing the same correction.
Fixes KeyError: 'created_at' on PRs with no comments/reviews.
Includes the individual-check-status fix (use "status" not "state").
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Gitea Actions API uses "status" (pending/success/failure) not "state"
for individual status entries. The "state" field is null for pending
runs. This caused all_check_statuses to show Python null instead of
"pending" for queued jobs.
Also verified on PR #391 and PR #393 — individual checks now correctly
display "pending" while combined_state is "pending" (CI_PENDING verdict).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
SOP-6 + CI gate checker for Gitea PRs. Detects:
- Signal 1: Author-aware agent-tag comment scan (tier-aware)
- Signal 2: REQUEST_CHANGES reviews state machine
- Signal 3: Staleness detection (SOP-12)
- Signal 6: CI required-checks awareness
Post `[gate-check-v3] STATUS:` comment on PRs. CLI + Gitea Actions
workflow (cron hourly + PR-triggered).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documents four persistent operational findings from the 2026-05-11
Gitea migration and CI noise investigation:
1. Runner network isolation (git remote unreachable from container)
2. continue-on-error only works at step level, not job level
3. workflow_dispatch.inputs not supported
4. fetch-depth:0 on actions/checkout times out
References PR #441 (harness-replays detect-changes fix) and
Task #173 (pre-clone manifest deps pattern).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cherry-picked from PR #452 (fix/canvas-test-and-design-fixes) which
was closed without merge during the PR #443 cascade. The fix adds a
mockPost reference so individual tests can reset the POST mock cleanly
instead of queueing multiple resolved/rejected values.
Without this, the "shows an error toast when POST fails" and "keeps
the card visible when POST fails" tests queue two responses from
beforeEach's mockResolvedValue({}) and the second mockRejectedValueOnce()
call, causing non-deterministic test outcomes.
Fixes test failures in ApprovalBanner suite.
Re-applies PR#462 on current main (PR#443 merged first and renamed
canary-staging.yml -> staging-smoke.yml, conflicting #462).
Swept 6 files (15 secret-ref flips):
- .gitea/workflows/staging-smoke.yml (3 refs + drop continue-on-error + add notify-on-failure step)
- .gitea/workflows/e2e-staging-saas.yml (3 refs)
- .gitea/workflows/e2e-staging-sanity.yml (3 refs)
- .gitea/workflows/e2e-staging-canvas.yml (3 refs)
- .gitea/workflows/e2e-staging-external.yml (3 refs)
- tests/e2e/STAGING_SAAS_E2E.md (1 heading flip + 1 historical-rename breadcrumb)
Each workflow keeps one inline breadcrumb comment pointing back to
the old name and internal#322.
staging-smoke is the 30-min canary cadence for the entire staging
SaaS stack; silent failure (continue-on-error: true) masked exactly
the regressions the smoke exists to surface, same class as PR#461
(`sweep-stale-e2e-orgs`). Dropped continue-on-error from the smoke
job + added a fail-loud `if: failure()` Notify step mirroring
PR#461. The four other `e2e-staging-*` workflows KEEP
continue-on-error: true per RFC #219 §1 — they are advisory.
Excluded from this PR:
- .gitea/workflows/sweep-stale-e2e-orgs.yml (PR#461 owns)
- .gitea/workflows/staging-verify.yml (only references the plural MOLECULE_STAGING_ADMIN_TOKENS canary-fleet secret, out of scope)
- scripts/staging-smoke.sh (same — plural only)
- docs/architecture/canary-release.md (same — plural only)
- .github/ mirror tree (separate scope per reference_molecule_core_actions_gitea_only)
Verified locally: yaml.safe_load clean on all 5 workflows; grep
returns ZERO non-breadcrumb references in the swept files; the
plural MOLECULE_STAGING_ADMIN_TOKENS references in
staging-verify.yml / scripts/staging-smoke.sh / canary-release.md
are intentionally untouched.
Refs: internal#322, PR#461, feedback_rename_pr_and_edit_pr_conflict_sequence
Gitea Actions runners cannot reach https://git.moleculesai.app over HTTPS
(runbooks/gitea-operational-quirks.md §runner-network-isolation).
fetch-depth: 0 on actions/checkout triggers a full repo history fetch
that times out at ~15s, causing the workflow to fail on Gitea runners
(main RED, issue #460).
Fix: use fetch-depth: 1 (shallow clone) and explicitly fetch tags with
git fetch origin --tags --depth=1. The collision check (git tag --list)
still works since we only need the most recent tag, not full history.
git push of the new tag works on a shallow clone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Follows up on #432 (merged). Extracts _check_delegation_results_pending()
from the inline guard in _run_idle_loop() so tests can call the real
production function directly via patch(builtins.open, ...).
Fixes#401: the previous test used a mirror copy of the guard logic,
which risks drifting from the production implementation over time.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PurchaseSuccessModal tests used a fixed 50ms setTimeout to wait for the
dialog to appear after React useEffect batch + createPortal. This was
flaky because React's rendering timing varies.
Replace waitForDialog() fixed-delay with waitFor() polling — the test
waits exactly as long as React needs, no more. Update all dismiss tests
to use act(() => setTimeout(...)) after vi.useRealTimers() for reliable
real-timer behavior.
Result: 18/18 tests pass (was 14/18 with 4 timing-related failures).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Gitea Actions quirk: continue-on-error: true only works at the step level,
not the job level (opposite of what the docs imply). Without step-level
continue-on-error, the detect-changes job was reporting status=failure
despite job-level continue-on-error: true.
Two-part fix:
1. continue-on-error: true on both the fetch and decide steps — belt-and-
suspenders against any remaining exit code leaks.
2. || true on DIFF=$(git diff ...) — git diff exits 1 when BASE is not
in local history (shallow checkout / unfetched commit). With
set -euo pipefail, that made the decide step itself fail. The empty
diff from the || true means "no changes" → run=false is correct;
the harness runs unconditionally when the fetch times out anyway.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds explicit 55s timeout and verbose output to the git fetch step so
the failure is diagnosed in CI logs rather than silent 15s timeout.
55s is well within the 60-min job timeout; enough for cold TCP handshake
+ one git pack transfer on a local network.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
git fetch origin <sha>:<sha> is not valid syntax for fetching an arbitrary
commit (git needs a ref to locate the commit on the remote). Switch to
git fetch origin main --depth=1 which fetches the main branch tip + its
immediate parent. The base commit is the parent of the PR head on main,
so depth=1 is sufficient.
github.event.pull_request.base.ref = "main" (confirmed from API) — this
is the branch name, not the SHA. git fetch origin main --depth=1 fetches
the branch tip and one ancestor, giving us the base commit in a single cheap
network call.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>