Skip to content

Document the live-test harness, the CI gate, and Indeterminate in AGENTS.md - #123

Merged
stephane-segning merged 1 commit into
mainfrom
claude/agents-md-m2-update
Aug 7, 2026
Merged

Document the live-test harness, the CI gate, and Indeterminate in AGENTS.md#123
stephane-segning merged 1 commit into
mainfrom
claude/agents-md-m2-update

Conversation

@stephane-segning

Copy link
Copy Markdown
Contributor

Summary

Brings AGENTS.md (which CLAUDE.md symlinks to) up to date after four PRs landed in one session: #118 (testcontainers-backed live-Postgres harness + CI wiring), #120 (gate stabilisation), #119 (ProviderError::Indeterminate), #121 (fake Orange + chaos suite).

Documentation only. No code, schema, or migration changes.

Intent

The agents behind #119/#121 updated AGENTS.md inline for their own work, but the single most consequential change of the session was absent entirely: sms-test-support appeared zero times, and nothing recorded that CI now runs the 14 live-Postgres suites at all. Before #118, .github/workflows/ci.yml ran a bare cargo test --workspace with no --ignored, so every live suite was silently skipped in CI and had only ever been run by hand — the same shape of gap this file already blames for #29's claim suite sitting unrun for a milestone while hiding a policy bug.

Source of truth: #118, #119, #120, #121 as merged, plus #122 for the undelivered dead-end.

Scope

  • New section — "The live suites run in CI now": the harness's five load-bearing constraints, each written with the failure that taught it (a static-held container handle leaking 56 containers because Drop never runs for statics; label-scoped cleanup, since an image-scoped sweep would destroy a developer's own running database; per-binary databases, because a shared one let kill9_reclaim_live's real dispatch subprocess claim other suites' messages; migration-content fingerprinting, because an existence check silently served a stale schema; and the global container name that makes concurrent local test runs corrupt each other). Also records that ca653a1's mutex was never applied to two suites, both of which flaked in CI within hours of Add a testcontainers-backed live-Postgres harness; wire it into CI (#102) #118 running them for the first time.
  • New paragraph on ProviderError::Indeterminate: the connect-vs-read timeout predicate and why inverting it is harmful in both directions, the routed -> uncertain edge it required, the providerMessageRefAlt stamp that keeps such messages resolvable, and the explicit tradeoff — a possibly lost message in exchange for never sending a duplicate, which is a product decision rather than a free win.
  • CLI-skew warning moved to where the danger is: the installed cratestack CLI is 0.7.4 against a pinned =0.6.7 library and emits FK DDL the pin never produces. That finding previously lived only in an unrelated paragraph ~150 lines from the two places that actually tell you to run cratestack migrate diff. Now stated at both.
  • Commands: adds just test-live / just test-live-clean, notes the manual createdb vsms_check flow is no longer needed for the Rust live suites, and warns against concurrent live-test runs.
  • Invariants section: adds the missing-hasRole('system') gap as an explicitly unguarded failure mode, now found seven times (App, AppClient, SenderIdRegistration, OperatorPrefixRule, Provider, Job, Message, DeliveryReceipt). The three existing entries each turned a silent failure loud; this one has no equivalent, which is precisely why it keeps recurring.
  • Links the undelivered finding to #122.

Verification

  • just parity green — and it now reports 25 message edges rather than 24, independently confirming Add ProviderError::Indeterminate for a submit that timed out after sending #119's routed -> uncertain edge is present in both the diagram and the transition table.
  • Documentation-only: no code paths, schema, or migrations touched (git diff --stat is a single file).
  • Every claim was checked against the merged source rather than the agents' summaries — including one correction made during the session, where a brief of mine wrongly listed RetryThisProvider as a ProviderError variant when it belongs to RoutingConsequence.

Screenshots/Evidence

N/A — prose-only documentation change.

Risk Assessment

None. Additive documentation; no behaviour affected.

AI Usage Declaration

Written by Claude Code (Claude Opus 5) under my direction, summarising work from the same session that produced and merged #118#121, each of which I reviewed and merged myself.

  • I verified the harness constraints against crates/sms-test-support as merged, not against agent reports.
  • The failures cited (container leak, stale schema, cross-binary message theft, the two suites missing the mutex, the CI-skipped suites) were each reproduced or observed directly during the session.
  • I confirmed the #[ignore]/just test-live workflow and the parity edge count by running them.
  • I take responsibility for this being an accurate account of what landed and why.

Reviewer Focus

Whether the new "live suites run in CI now" section is pitched correctly — it is deliberately long because five separate constraints there are each one-mistake-away from silently reintroducing a real defect, but it is the longest single addition to this file and worth a judgement call on length.

…NTS.md

Four PRs landed in one session (#118 harness, #120 gate stabilisation,
#119 ProviderError::Indeterminate, #121 fake Orange + chaos suite) and the
context file only picked up what the last two agents wrote inline. The
biggest omission was the most consequential change: `sms-test-support` and
the fact that CI now runs the 14 live-Postgres suites at all — previously
`cargo test --workspace` ran without `--ignored`, so they were skipped in
CI and had only ever run by hand.

Records, in each case why it exists rather than just that it does:

- The harness's five load-bearing constraints, each learned by something
  breaking: no container handle in a `static` (Drop never runs for statics,
  which leaked 56 containers), label-scoped cleanup only (an image-scoped
  sweep would destroy a developer's own database), one database per test
  binary (a shared one let a real dispatch subprocess steal other suites'
  messages), migration-content fingerprinting (an existence check served a
  stale schema silently), and the global container name that makes
  concurrent test runs corrupt each other.
- That `ca653a1`'s mutex was never applied to two suites, both of which
  flaked in CI within hours of #118 running them for the first time.
- `Indeterminate`'s connect-vs-read predicate, the `routed -> uncertain`
  edge it needed, and the fact that it trades a possibly lost message for
  never sending a duplicate — a product decision, not a free win.
- A CLI-skew warning placed at both sites that tell you to run
  `cratestack migrate diff`, since the installed 0.7.4 CLI emits DDL the
  pinned 0.6.7 library never does. The warning previously existed only in
  an unrelated paragraph 150 lines away from the commands themselves.
- The missing-`hasRole('system')` gap as an explicitly *unguarded* failure
  mode, now found seven times. The three entries above it each turned a
  silent failure loud; this one has no equivalent, which is why it recurs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a70266a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@lightbridge-assistant lightbridge-assistant 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.

🅵 Fast automated pass — SAST + a quick, diff-scoped look (no repo-wide retrieval). For a deeper, repo-aware review, mention @lightbridge-assistant on this PR.

Documentation-only change to AGENTS.md; no code, no secrets, and SAST is clean. I checked the added prose for internal consistency and found one provable accuracy defect: the new "hasRole('system') gap found N times" paragraph enumerates eight model names yet claims "seven separate times", and its count (and the sibling six-before list in the same hunk) disagrees about whether Message (#96) is a counted instance. Recorded as a P2; everything else in the added text is consistent and non-blocking.


🤖 AI-generated review — treat it as untrusted, verify before acting; a human owns the final decision (AI governance).

Comment thread AGENTS.md
- **`crates/sms-api/src/errors.rs`** — `map_database_error` turns SQLSTATE `SM001` into `CoolError::Conflict` (409) and `23505` into a named conflict. Untranslated, an illegal transition is a `500 DATABASE_ERROR`, which callers retry and operators read as a gateway fault. Genuine database faults stay 500 on purpose.

**And one failure mode that is still *not* guarded, which is why it keeps happening.** A model whose `@@allow` omits `hasRole('system')` does not error — CrateStack's list-route policy denial is row-level filtering to an **empty array** (see #97's finding on `GET /oauth_signing_keys`), so an internal system-context read just quietly returns nothing, and the calling code behaves as though the table were empty. That has now been found **seven separate times**, always live and never by review: `App`, `AppClient`, `SenderIdRegistration`, `OperatorPrefixRule` (#94), `Provider`, `Job` (#100), `Message` list/detail (#96, which is why #29's claim loop had been returning zero rows for a milestone), and `DeliveryReceipt` (#121). Seven repetitions of one mistake is a missing invariant, not seven oversights — the other three entries above each turned a silent failure into a loud one, and this one has no equivalent. A golden test asserting that every model a system context must read actually admits one would end it; until someone writes it, expect an eighth.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 correctness

Instance count off by one (8 listed, "seven")

The tally is off by one and disagrees with the paragraph just above. This sentence enumerates eight distinct models — App, AppClient, SenderIdRegistration, OperatorPrefixRule (#94), Provider, Job (#100), Message list/detail (#96), and DeliveryReceipt (#121) — but claims "found seven separate times" and "Seven repetitions". Meanwhile the "two real findings" paragraph above (this same hunk) calls DeliveryReceipt the "seventh instance" with only six before it (AppJob), omitting Message (#96). Message is recorded elsewhere in this file as a genuine instance of this same gap (see the #96/#29 claim-loop discussion), so it should be counted — making the correct total eight, not seven. Worth reconciling the count and both enumerations so the permanent-invariant argument ("seven oversights") isn't built on a miscount.

Evidence: AGENTS.md line 132: "That has now been found seven separate times, always live and never by review: App, AppClient, SenderIdRegistration, OperatorPrefixRule (#94), Provider, Job (#100), Message list/detail (#96…), and DeliveryReceipt (#121). Seven repetitions of one mistake…" — eight names listed, "seven" claimed. Contrast line ~108's "the seventh instance … recorded six times before (App, AppClient, SenderIdRegistration, OperatorPrefixRule, Provider, Job)" which omits Message.

Was this useful? React 👍/👎 to give us feedback

@stephane-segning
stephane-segning merged commit 30bf1ab into main Aug 7, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant