generated from john/python-template
claude-sonnet-5 review: Phase 1 implemented by gpt-5.3-codex
Quality Gate / gate (push) Failing after 12s
Quality Gate / gate (push) Failing after 12s
This commit is contained in:
@@ -5,7 +5,7 @@ model: openai/gpt-5.3-codex
|
||||
[document body typewritten]
|
||||
BY WAY OF INTRODUCTION:-
|
||||
|
||||
These few paragraphs of introduotion [sic] may help you read BOOK 2 which covers a wider range than did BOOK 1 (Pioneer Days).
|
||||
These few paragraphs of introduction may help you read BOOK 2 which covers a wider range than did BOOK 1 (Pioneer Days).
|
||||
|
||||
BOOK 1 had 54 pages; 14 chapters. BOOK 2 has 70 pages; 18 chapters. BOOK 1 consisted largely of first generation family history. BOOK 2 throws more light on the second generation. Sidney promises a BOOK 3 and that may begin to do justice to the third generation. We suggest that Sidney get the help of Louis Shinn who has a chapter in this book (Chapter 16 - The Last 25 Years on the Doumecq Plains. Louis has the gift of seeing, recalling and telling. One sentence in his chapter gives a great tribute to the Doumecqers--so far as he knows no one on the Doumecq Plains went on relief during the depression. That in a nutshell shows the sturdy character of the residents of the Doumecq Plains.
|
||||
|
||||
@@ -13,6 +13,6 @@ We promised in BOOK 1 that in BOOK 2 we would give the story of the trip of John
|
||||
|
||||
Some who get this book will consider the group picture the best thing in the book. It took a lot of preliminary photographing to reduce some pictures, enlarge others and bring out the tin types. We wish that instead of 44 faces we could have given 88. Do not blame Ethel Cochran-Shinn for the selection. She furnished enough pictures but we had to take only part of them. We think there are great possibilities in reproducing old pictures. We wish we had a Pickard group. Some Pickard descendant may wish to make a collection.
|
||||
|
||||
We are much impressed with the future possibilities of getting a complete genealogy of the Pickard family. Mr. Cochran has a fine chapter on the Pickards but to date we have not had the pleasure of finding all of the family dates. We had intended to give more family data in this book but it takes time to get the correct dates. Often times it requires trips to cemeteries to get dates on the tombstones. Winter is no time to collect dates on tombstones.
|
||||
We are much impressed with the future possibilities of getting a complete geneology [sic] of the Pickard family. Mr. Cochran has a fine chapter on the Pickards but to date we have not had the pleasure of finding all of the family dates. We had intended to give more family data in this book but it takes time to get the correct dates. Often times it requires trips to cemeteries to get dates on the tombstones. Winter is no time to collect dates on tombstones.
|
||||
|
||||
~2~
|
||||
|
||||
@@ -3,6 +3,9 @@ provider: openrouter
|
||||
model: openai/gpt-5.3-codex
|
||||
---
|
||||
[document body typeset]
|
||||
JOHN E. COCHRAN
|
||||
FAMILY ASSOCIATION
|
||||
|
||||
Family Only
|
||||
Home | Sibling's Stories | 1st Cousins | Ancestor's Stories | Reunion History | Next Reunion | JECMEF
|
||||
|
||||
@@ -38,8 +41,7 @@ along the icebergs and the walrus were 'heisted' on board by the use of the cran
|
||||
tons of freight and the beasts were so huge that they made the pulleys just creak. They were
|
||||
over 12 feet long, as big around as three cows, had no feet but toenails on their flippers or
|
||||
flappers, no head but their body just suddenly ended with a hole for a mouth and big bristles
|
||||
|
||||
[photograph of people standing outdoors in snow]
|
||||
[photograph of people standing in snow]
|
||||
|
||||
all around it similar to a currycomb in coarseness; no ears but huge tusks of ivory. They are
|
||||
the most repulsive looking animals imaginable and tho I have always read about them I never
|
||||
@@ -63,9 +65,9 @@ bears with faces. I guess they had never seen white women, not so many at one ti
|
||||
We went ashore in 2 life boats and a launch pulling them. On the launch was a six piece band
|
||||
playing and the rear of the last life boat was the movie man. 'Twas very thrilling.
|
||||
|
||||
The other place we stopped was at Whalen, a trading post in Siberia. There these 'towerists'
|
||||
The other place we stopped was at Whalen, a trading post in Siberia. There these 'towerists'[sic]
|
||||
went wild. They rushed helter-skelter, hither and thither, here and there, trying to find
|
||||
something to buy. Prices raised right before your eyes. One would but something for $1.00
|
||||
something to buy. Prices raised right before your eyes. One would but[sic] something for $1.00
|
||||
and the next might have to pay $2.00, $4.00 or $10.00. That made no difference. They had to
|
||||
have it. One man I was sort of taking care of, tho he had his son along for the purpose,
|
||||
bought 2 ivory tusks, 1 pup, 2 moccasins, 3 or 4 billikens, 6 or 8 ivory and silver rings, one
|
||||
@@ -81,7 +83,7 @@ We got home yesterday morning at 5 a.m. but missed the first lighter in so had t
|
||||
until 2:30. The girls had prepared a big meal for us and invited up the Hartfords and then let
|
||||
us talk. Miss Saville talked quite a bit. Any how if you folks don't like this I don't care, it is
|
||||
all I had to write about and I know Buster'ud listen anyway and I'd soak ole Peter's head if he
|
||||
didn't and Polly would in my lap and I don't know much about the youngest one of yours so
|
||||
didn't and Polly would [sit] in my lap and I don't know much about the youngest one of yours so
|
||||
likely he would be squawling. But we did surely enjoy our trip and were gone just long enuf.
|
||||
|
||||
I expect there were 150 passengers on board and almost or more of the crew and helpers. We
|
||||
@@ -115,4 +117,4 @@ Reprinted from Cochran Chronicles, Volume 9, Number 1, November 1986
|
||||
|
||||
Up
|
||||
|
||||
jecochranclan.org ~ Contact webmaster
|
||||
jecochranclan.org - Contact webmaster
|
||||
|
||||
@@ -3,30 +3,31 @@ provider: openrouter
|
||||
model: openai/gpt-5.3-codex
|
||||
---
|
||||
[document body mixed]
|
||||
JOHN ISBILL R. T. MOSER
|
||||
JOHN ISBILL R. T. MOSER
|
||||
|
||||
ISBILL & MOSER
|
||||
DEALERS IN
|
||||
GENERAL MERCHANDISE
|
||||
|
||||
Vonore, Tenn., [handwritten: July 27-] 191[handwritten: 2]
|
||||
Vonore, Tenn., [handwritten: May 27-] 191[handwritten: 3?]
|
||||
|
||||
[handwritten: Dear Uncle Aunt & Cousins
|
||||
I was at home a
|
||||
few nights ago & saw a
|
||||
letter from your folks, so
|
||||
I decided to write you
|
||||
a few lines in regards of
|
||||
I am [contemplating?] a
|
||||
a few lines myself &
|
||||
am contemplating a
|
||||
trip out west next summer
|
||||
& want [lots?] of [olders?] to go
|
||||
where I am from.
|
||||
& want lots of places to go
|
||||
where I can stop.
|
||||
|
||||
Am getting
|
||||
up in years & wondering,
|
||||
up in years & unmarried,
|
||||
so you see the object of
|
||||
my trip, is to get a wife
|
||||
If there is any old maids
|
||||
my trip, is to get a wife.
|
||||
If there is any old maid
|
||||
or widows out there I
|
||||
want you to [hire?] them
|
||||
at [one?] [find?] me at there
|
||||
want you to [illegible] them
|
||||
at [illegible] me at them
|
||||
as soon as I get there.]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
from datetime import UTC
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
@@ -153,10 +154,33 @@ class TestJobService:
|
||||
finally:
|
||||
event.remove(bind, "before_cursor_execute", capture)
|
||||
|
||||
selects = [item for item in statements if item.lstrip().upper().startswith("SELECT")]
|
||||
assert len(selects) == 1, selects
|
||||
assert "LIMIT" in selects[0].upper()
|
||||
assert "JOIN" not in selects[0].upper()
|
||||
claim_sql = [
|
||||
item
|
||||
for item in statements
|
||||
if item.lstrip().upper().startswith(("SELECT", "UPDATE"))
|
||||
]
|
||||
assert len(claim_sql) == 1, claim_sql
|
||||
assert "LIMIT" in claim_sql[0].upper()
|
||||
assert "JOIN" not in claim_sql[0].upper()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_claim_next_queued_job_is_atomic_on_sqlite(
|
||||
self,
|
||||
job_service: JobService,
|
||||
document_service: DocumentService,
|
||||
):
|
||||
document = await document_service.create_document(Document(id=uuid4(), name="atomic-claim-doc"))
|
||||
queued_job = await job_service.create_job(Job(document_id=document.id, status=JobStatus.QUEUED))
|
||||
|
||||
async def claim_once():
|
||||
claimed = await job_service.claim_next_queued_job()
|
||||
return claimed.id if claimed is not None else None
|
||||
|
||||
first_claim, second_claim = await asyncio.gather(claim_once(), claim_once())
|
||||
|
||||
assert [first_claim, second_claim].count(queued_job.id) == 1
|
||||
assert [first_claim, second_claim].count(None) == 1
|
||||
assert await job_service.claim_next_queued_job() is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_job_persists_provider_and_model(
|
||||
|
||||
@@ -14,6 +14,7 @@ from transcription.errors import ErrorCategory
|
||||
from transcription.services.documents import DocumentDeleteBlockedError
|
||||
from transcription.services.documents import DocumentService
|
||||
from transcription.services.errors import SourceDeleteBlockedError
|
||||
from transcription.services.errors import TranscriptionError
|
||||
from transcription.services.evidence import EvidenceService
|
||||
from transcription.services.jobs import JobService
|
||||
from transcription.services.people import PeopleError
|
||||
@@ -190,6 +191,37 @@ async def test_transcription_service_job_source_crud_uses_caller_session(default
|
||||
assert len(await transcriptions.list_job_sources(job_id=job.id)) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_job_source_rejects_duplicate_job_source_membership(default_session_factory):
|
||||
documents = DocumentService(session_factory=default_session_factory)
|
||||
jobs = JobService(session_factory=default_session_factory)
|
||||
transcriptions = SourceService(session_factory=default_session_factory)
|
||||
|
||||
document = await documents.create_document(Document(id=uuid4(), name="duplicate-job-source-doc"))
|
||||
job = await jobs.create_job(Job(document_id=document.id))
|
||||
source = await transcriptions.create_source(
|
||||
Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="duplicate.jpg",
|
||||
filename="duplicate.jpg",
|
||||
file_path="uploads/duplicate.jpg",
|
||||
file_hash="d" * 64,
|
||||
file_size_bytes=1,
|
||||
)
|
||||
)
|
||||
await transcriptions.create_job_source(
|
||||
JobSource(job_id=job.id, source_id=source.id, status=JobSourceStatus.PENDING)
|
||||
)
|
||||
|
||||
with pytest.raises(TranscriptionError) as duplicate:
|
||||
await transcriptions.create_job_source(
|
||||
JobSource(job_id=job.id, source_id=source.id, status=JobSourceStatus.PENDING)
|
||||
)
|
||||
|
||||
assert duplicate.value.category == ErrorCategory.CONFLICT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_document_detail_loads_linked_person_relationship(default_session_factory):
|
||||
documents = DocumentService(session_factory=default_session_factory)
|
||||
|
||||
+9
-3
@@ -123,14 +123,19 @@ async def test_create_all_declares_hot_path_indexes(tmp_path):
|
||||
await create_all(engine=runtime.engine)
|
||||
async with runtime.engine.connect() as connection:
|
||||
|
||||
def collect(sync_connection) -> dict[str, list[list[str]]]:
|
||||
def collect(sync_connection) -> tuple[dict[str, list[list[str]]], list[list[str]]]:
|
||||
database = inspect(sync_connection)
|
||||
return {
|
||||
indexes = {
|
||||
table: [index["column_names"] for index in database.get_indexes(table)]
|
||||
for table in ("job", "source", "job_source", "document", "document_person")
|
||||
}
|
||||
job_source_unique = [
|
||||
constraint["column_names"]
|
||||
for constraint in database.get_unique_constraints("job_source")
|
||||
]
|
||||
return indexes, job_source_unique
|
||||
|
||||
indexes = await connection.run_sync(collect)
|
||||
indexes, job_source_unique = await connection.run_sync(collect)
|
||||
|
||||
assert ["status", "date_created"] in indexes["job"]
|
||||
assert ["document_id"] in indexes["job"]
|
||||
@@ -138,6 +143,7 @@ async def test_create_all_declares_hot_path_indexes(tmp_path):
|
||||
assert ["preferred_execution_attempt_id"] in indexes["source"]
|
||||
assert ["job_id"] in indexes["job_source"]
|
||||
assert ["source_id"] in indexes["job_source"]
|
||||
assert ["job_id", "source_id"] in job_source_unique
|
||||
assert ["document_type_id"] in indexes["document"]
|
||||
for column in ("document_id", "person_id", "role_id"):
|
||||
assert [column] in indexes["document_person"]
|
||||
|
||||
@@ -238,6 +238,22 @@ class TestJobSourceModel:
|
||||
assert fetched.status == JobSourceStatus.PENDING
|
||||
assert set(JobSource.model_fields) == {"id", "job_id", "source_id", "status"}
|
||||
|
||||
def test_job_source_membership_is_unique_per_job_and_source(self, session):
|
||||
document = _persist_document(session)
|
||||
job = _persist_job(session, document)
|
||||
source = _persist_source(session, document)
|
||||
_persist_job_source(session, job, source)
|
||||
|
||||
session.add(
|
||||
JobSource(
|
||||
job_id=job.id,
|
||||
source_id=source.id,
|
||||
status=JobSourceStatus.PENDING,
|
||||
)
|
||||
)
|
||||
with pytest.raises(IntegrityError):
|
||||
session.commit()
|
||||
|
||||
|
||||
class TestRelationships:
|
||||
def test_document_exposes_jobs_sources_and_people(self, session):
|
||||
|
||||
Reference in New Issue
Block a user