Skip to content
This repository was archived by the owner on Oct 24, 2026. It is now read-only.

chore(integration): merge rehearsal for the 10 open PRs, with local proof - #301

Closed
PetrefiedThunder wants to merge 32 commits into
mainfrom
claude/merge-pull-requests-plan-emtaye
Closed

PetrefiedThunder wants to merge 32 commits into
mainfrom
claude/merge-pull-requests-plan-emtaye

Conversation

@PetrefiedThunder

@PetrefiedThunder PetrefiedThunder commented Aug 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

An integration branch that merges the remaining open PRs (#290, #292, #293, #294, #297, #299), plus the validation evidence for merging them. This is a pre-flight rehearsal, not a replacement for the individual PRs — see Recommended merge order below.

#291 is deliberately excluded: it is a breaking change. See Blocker below.

Status 2026-08-17 ~06:10Z.

Blocker: #291 (mcp <2 → <3) breaks the app

The <2 bound is load-bearing, exactly as its own inline comment says. With mcp==2.0.0 installed, app/main.py fails to import:

app/routers/mcp_public.py:40: from mcp.shared.exceptions import McpError
ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'

mcp 2.x renamed McpError → MCPError. The symbol is imported in app/routers/mcp_public.py:40 and app/routers/mcp_standard.py:68. Recommendation: close #291 (or convert it to a port that renames the import and re-checks mcp.server.lowlevel, mcp.server.streamable_http, RequestBodyLimitMiddleware, and mcp.server.fastmcp against the 2.x API). The PR carries an approval; the approval predates this evidence.

Recommended merge order

Six PRs remain, no cross-conflicts except one adjacent-line collision in requirements.txt:

  1. chore(deps): update greenlet requirement from >=3.5.4 to >=3.5.5 #290 greenlet, chore(deps): update alembic requirement from >=1.19.0 to >=1.19.1 #293 alembic — clean.
  2. chore(deps): update stripe requirement from >=15.4.0 to >=15.5.0 #292 stripe — conflicts with chore(deps): update greenlet requirement from >=3.5.4 to >=3.5.5 #290/chore(deps): update alembic requirement from >=1.19.0 to >=1.19.1 #293 only because the three pins are adjacent lines. Trivial resolution (take all three bumps), or just click Update branch.
  3. fix(discovery): manifest generation must not crash on an oversized price #297 (mcp_generator OverflowError), fix(state): release the aiosqlite worker thread at interpreter shutdown #299 (aiosqlite shutdown backstop) — disjoint code paths, no shared files. Both marked ready.
  4. feat(examples)+docs: run the interop experiment, write the demand instrument #294 (ACTA interop + interview script).
  5. Close chore(deps): update mcp requirement from <2,>=1.29.0 to >=1.29.0,<3 #291.

#296 merged 04:45Z. #300 merged 05:01Z. #298 merged ~05:5xZ.

#294's CHANGES_REQUESTED is CodeRabbit; its last review's one actionable item (parametrize test_missing_signer_identity_is_refused) is already implemented at head 0932b18.

Type of Change

Validation

CI: 14/14 green on heads b4e57d5 and 3a7e15b.

Run locally on the merged tree, re-verified after each main sync:

  • pytest -q -m "not proof" — 1321 passed, 31 skipped
  • pytest -q -m proof — 376 passed, 1 skipped
  • make prove-crash-recovery against a clean local PostgreSQL 16 — 13 passed (re-run after fix(permits): enforce expiry in the guarded reservation update; fold the 2026-08 research into docs/ip #298's permits change)
  • make trust-release-gate — passed (discovery drift, OpenAPI parity, simulation inventory parity)
  • ruff check . — clean
  • mypy app/ — no issues in 172 source files
  • python scripts/check_doc_references.py — 259 references across 242 files resolve
  • secret_scan (gitleaks) — green on CI
  • invariant_attack_proof — green on CI
  • no new claim contradicts SECURITY_LIMITATIONS.md

Risk

  • low — for this branch as a rehearsal. The merge itself introduces no new code beyond the dependency-pin resolution.

Notes:

  • This branch should probably not be merged as one commit. Landing it would put six PRs into main in a single squash and orphan the individual review threads. Its value is the evidence. Merge the PRs individually in the order given; if you'd rather land one merge, this branch is ready.
  • requirements.txt resolution keeps all three bumps: greenlet>=3.5.5, stripe>=15.5.0, alembic>=1.19.1, with mcp left at <2.

dependabot Bot and others added 29 commits August 17, 2026 00:18
Updates the requirements on [greenlet](https://github.com/python-greenlet/greenlet) to permit the latest version.
- [Changelog](https://github.com/python-greenlet/greenlet/blob/master/CHANGES.rst)
- [Commits](python-greenlet/greenlet@3.5.4...3.5.5)

---
updated-dependencies:
- dependency-name: greenlet
  dependency-version: 3.5.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
…trument

Continues the two open threads from docs/market-research-2026-08.md §8.3,
turning both from recommendations into artifacts.

The interop experiment has been run. examples/acta_receipt_interop.py
transcodes a signed portable receipt into the ScopeBlind ACTA envelope
(draft-farley-acta-signed-receipts) as a custom agentmiddleware:governed_invoke
receipt type: inner production signature verified over the exact signing_input
bytes exactly as b2a-verify-receipt does, outer Ed25519-over-JCS envelope with
issuer_id bound to the signing kid, and the ledger/idempotency/permit linkage —
the row no surveyed format defines — carried as first-class fields. The demo
runs against the checked-in public proof artifact and both signatures verify.

Fail-closed by design: unverified inner signatures, tampered signing_input,
kid mismatches, missing economic linkage, and floats in the JCS subset are all
refused, each with a negative test (8 tests total). Deliberately an experiment
in examples/, not an SDK export or route — WEDGE.md's freeze discipline stands,
and shipping it is a product call. The measured cost (~200 lines, no
trust-plane changes) replaces the estimate in §8.3.

The demand question has an instrument. docs/partner-interview-script.md is a
past-tense-only discovery script: incident excavation first, the product
unmentioned for 25 minutes, current mitigations treated as the real competitor,
money questions about past spend rather than hypothetical willingness, a
commitment test priced in a named engineer's afternoon, a per-call scoring
table, and a decision rule committed before the interviews (3/5 incidents +
2/5 commitments → paid-pilot conversation; incidents without commitment →
reposition around evidence; no incidents → the market isn't here yet). The
script explicitly forbids using the LangGraph citation to manufacture pain.

Also updates §7/§8.3 of the research doc to point at both artifacts, and the
changelog.

Tests: 51 passed across the new suite, wedge-honesty, and site contracts.
Ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
All 14 jobs on the previous run were refused in under two seconds with no
runner assigned and no step output — an Actions capacity/limit refusal,
not a test failure. No code changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
…rview-script rigor

Interop example:
- verify_portable_bundle now takes expected_issuer: the wrapper's issuer
  field is outside the signed bytes, so it is checked against the issuer
  bound to the key material in the trust-keys snapshot instead of being
  trusted on its own. Demo and roundtrip test pass the snapshot's issuer;
  a new negative test mutates issuer post-signing and is refused.
- verify_acta_receipt now rejects a signature block whose alg is not
  Ed25519 or whose sig is not a hex string; new test tampers only alg.
- Research doc no longer implies the issuer label itself is signed.

Interview script:
- One timing boundary: reveal at ~minute 25, framing says 25 minutes.
- §1 opens with a broad narrative prompt before the pointed probe, so
  incidents that don't fit our shape still get told.
- §2 no longer supplies 'idempotency keys'; it reuses the interviewee's
  own words (rule 5 marked as applying everywhere except §4).
- §3 adds the buyer question: last approver, budget owner, procurement.
- §3's vendor question is past-tense ('has the fix ever broken') instead
  of hypothetical.
- Commitment test requires observables on the call: named engineer, named
  staging environment, scheduled date — scoring table records each.
- Decision rule defines qualified_n, adds an unknown outcome, and defaults
  every unlisted pattern to more interviews, not a decision.

Tests: 53 passed (interop, wedge-honesty, site contracts). Ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
…nsistency

- verify_acta_receipt refuses an envelope whose issuer_id or signature kid
  is missing or empty, closing the None == None bypass where a valid
  signature could verify with no declared signer; regression test signs a
  body with neither field and asserts refusal.
- Commitment test uses one scheduling condition everywhere: date scheduled
  or a concrete scheduling step taken on the call, in the prompt, the
  scoring table, and the decision rule.
- Commitment gate explicitly marked pre-qualification, pointing at the
  stricter Pilot Acceptance Test in 30-day-customer-validation.md
  (partner-owned agent, partner-owned staging MCP tool, partner engineer,
  independent partner-side receipt verification).
- Paid-pilot selection is deterministic: earliest scheduled staging date,
  tie-break on buyer-evidence completeness, then interview order; 'the
  strongest one' removed.
- §2 opens with a neutral 'what, if anything, did you change' so a
  no-mitigation answer records as none instead of being presupposed away.

Tests: 11 interop tests passed. Ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
…test

- verify_portable_bundle refuses a bundle declaring a non-Ed25519 alg
  instead of silently verifying with Ed25519 and reporting a result the
  bundle's own metadata contradicts; negative test included.
- The signer-identity regression test is parametrized across absent and
  empty issuer_id and kid independently, so both validation branches stay
  covered.

Tests: 16 interop tests passed. Ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
… tests

Clears the one remaining non-blocking review warning (docstring coverage
below threshold). No behavior changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
Updates the requirements on [alembic](https://github.com/sqlalchemy/alembic) to permit the latest version.
- [Release notes](https://github.com/sqlalchemy/alembic/releases)
- [Changelog](https://github.com/sqlalchemy/alembic/blob/main/CHANGES)
- [Commits](https://github.com/sqlalchemy/alembic/commits)

---
updated-dependencies:
- dependency-name: alembic
  dependency-version: 1.19.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Updates the requirements on [stripe](https://github.com/stripe/stripe-python) to permit the latest version.
- [Release notes](https://github.com/stripe/stripe-python/releases)
- [Changelog](https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md)
- [Commits](stripe/stripe-python@v15.4.0...v15.5.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-version: 15.5.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
float() raises OverflowError — not ValueError — for an int too large to
represent, so a registry row carrying one made tools.json generation
raise instead of falling back. Catch it alongside the existing guards
and cover every invalid-price branch: NaN, ±inf, unparseable text,
non-numeric types, and oversized ints, in both the exact and non-exact
fields. A legitimately zero-priced tool is still advertised as
non-economic.

Closes the follow-up left open on #277.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1seEp4Pa4DtY1HMuJS3AX
…isional

#285 and #288 added verified, primary-source research to the repository and
changed no file in docs/ip/. The package was therefore ranking mechanisms
against an art landscape the project had already superseded. This corrects
that, and assembles a filing-ordered specification.

## The prior art the package was missing

`draft-farley-acta-signed-receipts` is the sharpest of it: Ed25519 over
JCS-canonicalized JSON, namespaced receipt types, and from -02 a
`spending_authority` type — reaching mechanisms 1, 3 and 4 at once. It was
nowhere in docs/ip, including the IDS list. Also absent: protect-mcp
(recorded as the closest competitor, emitting receipts verifiable without
calling the issuer), jamjet (signed chained receipts plus budget
enforcement), latch (idempotency plus budget caps), TraceAgent, and
microsoft/agent-governance-toolkit.

Separately, 02- ranked the guarded conditional UPDATE first without naming
the textbook technique it instantiates. Optimistic concurrency control
(Kung & Robinson, ACM TODS 6(2), June 1981, pp. 213-226) is now stated
outright, along with the fact that this repository uses the same technique
a second time in audit_chain.py — which an examiner may find. The
distinction that survives is narrow and is stated narrowly: a domain-cap
predicate rather than a version equality test, a zero-row outcome
classified into an actionable reason, and no retry loop.

## The ranking changed as a result

The settlement mechanisms held; the evidence mechanisms weakened, because
the evidence half of this category filled in during 2026 while the package
was being drafted. Offline verification drops from second to fourth: what
survives is the six-state taxonomy specifically — a key the verifier does
not hold resolving to UNKNOWN_KEY rather than to a tampering verdict — not
"offline verification," which is now table stakes. Set A and Set C carry
matching drafting notes.

## The SDK-release questions got narrower

One comfortable assumption did not survive: no workflow or script in this
repository downloads its own release assets, so the mechanical explanation
that would have made the four download counts self-evidently benign is not
present in the tree. The count is unexplained rather than explained.

Recorded from the authenticated API instead: the release and both assets
were produced by github-actions[bot]; updated_at equals published_at, so
the release has not been edited since 2026-08-07; and both asset SHA-256
digests, which are what lets anyone later establish what was in the
artifact on that date. Repository visibility could NOT be determined from
this environment — an unauthenticated probe traverses a proxy, and a
private repo returns 404 regardless, so neither code is evidence. That is
now stated rather than assumed.

## New: 07-provisional-specification.md

03- and 05- assembled into one continuous 112(a) written description in
filing order. Code citations are wrapped in [[brackets]] so counsel can
find and strip them; [not implemented] markers are retained deliberately.
Abstract is 146 words against the 150-word cap of 37 CFR 1.72(b).

## Validation

- 40 file:line citations across docs/ip verified against the tree
- 0 broken internal links
- scripts/check_doc_references.py: 249 refs across 242 files resolve
- ruff clean; pytest 1666 passed, 19 skipped
- Kung & Robinson citation verified against dblp and the ACM DOI rather
  than asserted from memory

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVvJpNRU9wp3WXowfeqtPU
aiosqlite.Connection composes its worker Thread without daemon=True, and
CPython joins non-daemon threads during shutdown. A durable-state SQLite
connection nobody closes therefore wedges the process at exit with no
traceback and no output. close() is the real cleanup path, but only two
callers reach it -- the FastAPI lifespan and the test teardown -- so any
script, REPL, or worker entrypoint that opens the backend hangs on exit.

This is the failure mode that cancelled CI at GitHub's six-hour limit.
That was fixed test-side only, leaving the class live for every other
consumer. Making the SQLite backend correctly reachable then made it
reachable in earnest.

Registers a process-wide backstop that stops tracked connections nobody
closed. Two details are load-bearing:

- It uses threading._register_atexit, NOT atexit. Plain atexit handlers
  run *after* the non-daemon join, so the obvious implementation can
  never break this hang -- confirmed by observing the ordering directly.
  The stdlib's own concurrent.futures.thread uses the same hook.
- It calls Connection.stop rather than close. stop is synchronous and
  tolerates a missing event loop by design, so no loop must survive
  until shutdown. Unlike daemonizing the thread, it closes in order and
  cannot truncate a write to a durable store.

A single module-level hook over a registry, rather than a hook per
connection, because _register_atexit has no unregister counterpart.
Forked children are guarded by owner pid so a child never closes a
connection its parent owns. Scope is SQLite only: neither the asyncpg
pool nor the redis client spawns a non-daemon thread.

Verified as an A/B/A on the acceptance gate -- a subprocess that opens
the backend and exits without closing it. With the backstop the process
exits 0; without it the same test returns 124. A backstop never seen
failing is not known to work.

Closes #287

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195WsXzT9kFxfxkrWQm4zhR
The harness instruments twelve commit boundaries; six scenarios reached
five of them, and PROOF_MATRIX recorded the other seven as a known gap.
This closes it with a table-driven boundary suite that kills a worker at
each remaining point and pins the disposition it must leave, taking
`prove-crash-recovery` from six scenarios to thirteen.

Every expectation was checked against the implementing code before being
asserted, which is what turned two of them from "observed behaviour"
into documentation fixes:

- An effect-free local crash is *not* released for retry.
  `failure-semantics.md` window E said the record is deleted so the key
  can retry, but `reconcile_stuck_records` scopes that to
  `operation_kind == "upstream_mcp"` -- a local tool's side-effect
  ordering is not observable to the reconciler, so the key is held in
  progress and cannot be reused without an operator.
- A reservation stranded before any charge stays stranded.
  `reconcile_budgets` only reclaims from permits that can no longer
  admit a charge, because a long-running call is indistinguishable from
  a dead one and an early reset could let a concurrent request overspend
  past max_credits. Recorded as a new window F.

Both are correct fail-closed choices that were simply never written
down, which is the same class of prose-outruns-code defect the
doc-reference gate was added for and cannot catch.

The new rows assert each record's own durable state rather than the
sweep's counters, which are cumulative across the shared database. Three
of them leave a needs-review record, so the narrative scenarios that
assert exact counters must keep running first; that dependency is now
called out in a comment where a future reader will hit it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qz8gaM1yVHVf2j2m6f1Vtx
… open

The authenticated API reports private: true as of 2026-08-17. That settles
the present state and only the present state — the API exposes current
visibility, not history, and the interval since 2026-08-07 is the part that
bears on whether the SDK sdist was ever publicly available.

Stated that way rather than as a clean answer, and the counsel question
updated to say what the API can and cannot close.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVvJpNRU9wp3WXowfeqtPU
Checks run in throwaway git worktrees under .claude/worktrees/. Those are
full repo copies — including .env.production and coverage artifacts — and
must never be committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsXYfTHDLiFNQ24R5JPN7H
Review caught that the two pre-existing scenarios asserted the sweep's
`idempotency_repaired` / `idempotency_needs_review` counters, which are
cumulative over every record the shared database still holds.
`stress_harness` is module-scoped and this module deliberately does not
truncate between tests, so those assertions silently depended on the
order the module ran in -- and this branch made that worse by adding
three more scenarios that leave a needs-review record.

I had documented the hazard in a comment instead of removing it. That
was the weaker choice: both assertions are now made against the seeded
call's own record, which is what each scenario is actually claiming.

Verified rather than assumed, with pytest-randomly installed locally and
then removed so the environment still matches CI:

- pre-fix code, shuffled with seed 1: both scenarios FAIL, on exactly the
  two counter assertions
- fixed code, shuffled with seeds 1 and 7: 13 passed
- fixed code, definition order: 13 passed; full suite 1666 passed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qz8gaM1yVHVf2j2m6f1Vtx
…1' into claude/merge-pull-requests-plan-emtaye
…' into claude/merge-pull-requests-plan-emtaye

# Conflicts:
#	requirements.txt
…-1ceo8u' into claude/merge-pull-requests-plan-emtaye
…x9f' into claude/merge-pull-requests-plan-emtaye
…stop' into claude/merge-pull-requests-plan-emtaye
…dc6h' into claude/merge-pull-requests-plan-emtaye
…points' into claude/merge-pull-requests-plan-emtaye
…esearch-qr05ry' into claude/merge-pull-requests-plan-emtaye
@vercel

vercel Bot commented Aug 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-middleware-web Ready Ready Preview Aug 17, 2026 6:03am

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_5c0da835-73f6-471c-97d1-e147a97a0ee0)

@coderabbitai

coderabbitai Bot commented Aug 17, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 41663d63-ba88-49ab-95f1-f13291266253

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

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

Copy link
Copy Markdown
Collaborator Author

CI is red here, and it is the repo-wide Actions failure described in the PR body — not this branch.

All 14 jobs in run 31989263403 failed within ~2 seconds of starting, produced no log output (log download returns HTTP 404), and the same thing happens on main (run 31984950047, 2026-08-17T01:26Z) and on every other open PR. main was green through 2026-08-15. Jobs are failing before any step executes, which points at the Actions runner/account side rather than at any diff.

No fix to push from here. The local results in the PR body — 1319 unit tests, 376 proof tests, 13/13 crash-recovery scenarios on real PostgreSQL 16, trust-release-gate, ruff, mypy, doc references — are what stands in for CI until Actions is restored. I'll re-check and report when it recovers.


Generated by Claude Code

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_262de4b5-2744-49f4-ac2d-9b949a75fbf8)

…uests-plan-emtaye

# Conflicts:
#	docs/ip/07-provisional-specification.md
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ffbb87ad-0ec4-491d-bc31-3b8ee68dc36b)

Copy link
Copy Markdown
Collaborator Author

Closing — this branch has served its purpose and is now unsafe to merge.

All nine PRs it was rehearsing are in main:

PR Merge commit
#296 refactor(demo): loopback-only live-loop proof fcc4b31
#300 test(crash): exercise every instrumented fault point a6254d8
#298 fix(permits) + docs(ip) c4760e4
#290 chore(deps): greenlet >=3.5.5 ba53d11
#293 chore(deps): alembic >=1.19.1 4941a31
#297 fix(discovery): oversized price 573190a
#299 fix(state): aiosqlite worker at shutdown 9cf5a17
#294 feat(examples)+docs: interop experiment e650c9e
#292 chore(deps): stripe >=15.5.0 a928fd6

Why closing rather than merging: #297 and #299 both advanced after this branch integrated them, and the versions that landed are the newer ones. This branch is now behind main on those files — merging it would revert roughly 438 lines, including #299's released-flag fix and its test_connection_stays_tracked_when_both_cleanup_paths_fail regression test. An integration rehearsal is only valid against the heads it rehearsed.

The requirements.txt resolution it proposed is what shipped: greenlet>=3.5.5, stripe>=15.5.0, alembic>=1.19.1, mcp held at <2.

#291 stays open and should be closed unmerged. It is the one PR from the original ten that was not merged, because widening the mcp bound to <3 breaks app/main.py at import — mcp 2.x renamed McpError → MCPError, imported at app/routers/mcp_public.py:40 and app/routers/mcp_standard.py:68. Details in the comment on that PR.


Generated by Claude Code

This branch was successfully deployed

1 active deployment
Preview — f916b2a1 Deployed Aug 17, 2026 by vercel[bot]
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants