conform

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package conform holds the shared conformance suite for the S1 spike queue backends (sqlitev4, postgresv4). Every backend runs the SAME tests through a thin harness: the backend owns how a fresh isolated database is created (FreshDSN), how a Store attaches to a dsn (OpenOn), and how raw seeding SQL reaches the engine (Exec/Begin, dialed via Dialect). Capability knobs (Caps) carry the S1 divergences the suites previously encoded as per-backend skip edits — a Cap stays false until the upstream engine grows the surface (ADR-0019).

The suites are sequential: StoreSuite registers no parallel subtests and the harness state (`active`) spans exactly one StoreSuite call.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func StoreSuite

func StoreSuite(t *testing.T, s Suite)

StoreSuite runs the full conformance suite against the backend harness.

func TestAppendFactDoesNotMaterializeTaskRows

func TestAppendFactDoesNotMaterializeTaskRows(t *testing.T)

TestAppendFactRejectsNothingTaskShaped — AppendFact is the sanctioned out-of-band writer; this pins its doc'd contract on the happy path only: no task row is created even when a task-like id is passed.

func TestAppendFactRecordsNonTaskFact

func TestAppendFactRecordsNonTaskFact(t *testing.T)

TestAppendFactRecordsNonTaskFact pins the session bridge's write path: a fact keyed by a synthetic "session:<id>" identity persists, gets a Seq and a Time, and never touches the tasks table.

func TestArchiveFactsBeforeKeepsProjections

func TestArchiveFactsBeforeKeepsProjections(t *testing.T)

TestArchiveFactsBeforeKeepsProjections (ADR-0006 prototype): terminal tasks' facts move to facts_archive; active tasks' facts stay hot; the tasks projection and Facts() keep working; the watermark is recorded.

func TestBandFilter

func TestBandFilter(t *testing.T)

TestBandFilter pins the PriorityMin/PriorityMax pushdown: the band filter sees the STORED priority (aging is scheduling, not state) and composes with CountTasks.

func TestCancelPendingOnly

func TestCancelPendingOnly(t *testing.T)

func TestCancelReasonStoredInFactDetail

func TestCancelReasonStoredInFactDetail(t *testing.T)

TestCancelReasonStoredInFactDetail pins the forensics contract: a --reason-style Cancel lands in the task.cancelled fact's detail ("reason" key), an empty reason stores none, and a cooperative cancel carries the operator's reason from the request fact onto the final cancelled fact.

func TestCancelRunningRequestAndHonour

func TestCancelRunningRequestAndHonour(t *testing.T)

TestCancelRunningRequestAndHonour pins the cooperative-cancel store contract: request (idempotent fact), observation, owner-guarded finalize.

func TestClaimAgingAccruesPerWindow

func TestClaimAgingAccruesPerWindow(t *testing.T)

func TestClaimAgingBonusCapped

func TestClaimAgingBonusCapped(t *testing.T)

func TestClaimAgingFlipsOrder

func TestClaimAgingFlipsOrder(t *testing.T)

func TestClaimAgingKeyedOnCreatedAtAcrossRequeue

func TestClaimAgingKeyedOnCreatedAtAcrossRequeue(t *testing.T)

func TestClaimAgingRespectsNotBefore

func TestClaimAgingRespectsNotBefore(t *testing.T)

func TestClaimCountsGroupsPerTask added in v0.4.1

func TestClaimCountsGroupsPerTask(t *testing.T)

func TestClaimDueTypesFiltersExecutorTypes added in v0.4.1

func TestClaimDueTypesFiltersExecutorTypes(t *testing.T)

func TestCompleteResetsLastError

func TestCompleteResetsLastError(t *testing.T)

func TestCompleteVerifiesLease

func TestCompleteVerifiesLease(t *testing.T)

func TestCountFactsByTypeSince

func TestCountFactsByTypeSince(t *testing.T)

func TestCountTasksMatchesList

func TestCountTasksMatchesList(t *testing.T)

TestCountTasksMatchesList pins that CountTasks and List agree under EVERY CLI filter combination (row: tq tasks --count can never drift from the listing it summarizes — the silent-cap census class). The seed spans both projects, both types, one completed, and one rate-limit-parked task so each filter has a known, non-trivial match set.

func TestDepsBlockUntilCompleted

func TestDepsBlockUntilCompleted(t *testing.T)

func TestDismissDead

func TestDismissDead(t *testing.T)

func TestEmptyTypeRejected

func TestEmptyTypeRejected(t *testing.T)

func TestEnqueueAndClaim

func TestEnqueueAndClaim(t *testing.T)

func TestEnqueueClaimBaseline10k

func TestEnqueueClaimBaseline10k(t *testing.T)

TestEnqueueClaimBaseline10k measures queue-op throughput at the round-5 baseline scale (10k tasks): enqueue rate, claim+complete rate, and a page-query. It asserts only CORRECTNESS (counts) — timings are printed for the FEATURES baseline and re-measured by hand. Skipped under -short.

func TestEnqueueDedupKey

func TestEnqueueDedupKey(t *testing.T)

func TestEnqueueFactDetailCarriesIdentity

func TestEnqueueFactDetailCarriesIdentity(t *testing.T)

TestEnqueueFactDetailCarriesIdentity pins the enqueue-fact wire contract the journal-drift audit replays against (tq audit --journal): identity and priority/dedup key ride the fact detail, and a zero priority is an EXPLICIT zero, not an omitted field — a thin detail would silently downgrade the audit's coverage for every modern task.

func TestEnqueueWithoutDedupKeyIndependent

func TestEnqueueWithoutDedupKeyIndependent(t *testing.T)

func TestFactsCursorBounded

func TestFactsCursorBounded(t *testing.T)

func TestFactsForTaskFiltersAndBounds

func TestFactsForTaskFiltersAndBounds(t *testing.T)

func TestFactsSinceByType

func TestFactsSinceByType(t *testing.T)

func TestFailPermanentDeadLettersImmediately

func TestFailPermanentDeadLettersImmediately(t *testing.T)

func TestFailRetriesThenDeadLetters

func TestFailRetriesThenDeadLetters(t *testing.T)

func TestFailureEvidenceDetailRoundTrips

func TestFailureEvidenceDetailRoundTrips(t *testing.T)

TestFailureEvidenceDetailRoundTrips pins the M12 contract the class stamping rides on: the failure evidence detail the worker hands to Fail survives the backend's fact persistence byte-for-byte enough for the class key to read back — autopsies and forensics depend on it.

func TestGetNotFound

func TestGetNotFound(t *testing.T)

func TestHeadSeq

func TestHeadSeq(t *testing.T)

func TestHeartbeatExtendsLease

func TestHeartbeatExtendsLease(t *testing.T)

func TestLastFactsReturnsTailInAscendingOrder

func TestLastFactsReturnsTailInAscendingOrder(t *testing.T)

func TestLeaseExpiryAllowsReclaim

func TestLeaseExpiryAllowsReclaim(t *testing.T)

func TestListFilters

func TestListFilters(t *testing.T)

func TestListOffsetPagination

func TestListOffsetPagination(t *testing.T)

func TestListPayloadContains

func TestListPayloadContains(t *testing.T)

TestListPayloadContains pins the Filter.PayloadContains pushdown: the substring matches the payload ALONE (id/project/type/last_error never over-match), it is case-insensitive with literal LIKE escaping, and Limit counts post-filter rows — the `tq tasks --verify-contains` hygiene audit leans on all three (09-39 §e1).

func TestListQueryLikeEscaping

func TestListQueryLikeEscaping(t *testing.T)

func TestListQueryPushdown

func TestListQueryPushdown(t *testing.T)

func TestListSeverityOrder

func TestListSeverityOrder(t *testing.T)

func TestListSinceFilter

func TestListSinceFilter(t *testing.T)

TestListSinceFilter pins the queue.Filter.Since SQL pushdown: inclusive lower bound on created_at (the exact boundary task is INCLUDED), and the boundary + 1ms excludes it. Both stores share the contract; the Postgres twin runs via the conformance battery.

func TestListSortAllowlist

func TestListSortAllowlist(t *testing.T)

TestListSortAllowlist (M18/F94): the allowlisted column sorts order the rows as named, and unknown values fall back to the default order instead of reaching SQL.

func TestLoadSnapshotScaleAt100k

func TestLoadSnapshotScaleAt100k(t *testing.T)

TestLoadSnapshotScaleAt100k pins the bounded-read architecture against the scale that motivated it: 100k tasks and 100k+ facts must render a dashboard snapshot in bounded time and memory — no full-journal or full-table scans. Skipped under -short; run explicitly with `go test ./internal/queue/ -run TestLoadSnapshotScaleAt100k`.

func TestMarkOrphanedRecordsStrandedTasks

func TestMarkOrphanedRecordsStrandedTasks(t *testing.T)

TestMarkOrphanedRecordsStrandedTasks: expired-lease Running tasks get a task.orphaned fact (once); live-lease tasks do not; task state is untouched — orphaning is an observation, the reclaim stays authoritative.

func TestMigrateAddsDedupKeyToOldDatabase

func TestMigrateAddsDedupKeyToOldDatabase(t *testing.T)

func TestMigrateAddsWatermarksTable

func TestMigrateAddsWatermarksTable(t *testing.T)

func TestNotBeforeDelays

func TestNotBeforeDelays(t *testing.T)

func TestParkRefusesNonPendingAndUnknown added in v0.4.1

func TestParkRefusesNonPendingAndUnknown(t *testing.T)

func TestParkSuppressesClaimsUntilRelease added in v0.4.1

func TestParkSuppressesClaimsUntilRelease(t *testing.T)

func TestParkedFilter

func TestParkedFilter(t *testing.T)

TestParkedFilter pins the --parked contract: only pending tasks with a future not_before match; completed/pending-due tasks never do.

func TestParkedRequeueNotResurrectableByStaleLease

func TestParkedRequeueNotResurrectableByStaleLease(t *testing.T)

TestParkedRequeueNotResurrectableByStaleLease pins the rate-limit park contract (13:29 report f16): a Requeue with a future not_before parks the task as pending with the lease fully cleared, so NOTHING can bring it back early — not the expired-lease reclaim branch (it only matches status='running'), and not the stale owner's lease-taking calls.

func TestPriorityOrdersClaims

func TestPriorityOrdersClaims(t *testing.T)

func TestPriorityScoreRoundtrip

func TestPriorityScoreRoundtrip(t *testing.T)

func TestPriorityScoresListAndDelete

func TestPriorityScoresListAndDelete(t *testing.T)

TestPriorityScoresListAndDelete pins the score-cache prune surface: the full list is ordered by item key, an empty key list deletes nothing, unknown keys are not an error, and only matching rows go.

func TestProjectExclusivityAcrossStoreHandles

func TestProjectExclusivityAcrossStoreHandles(t *testing.T)

TestProjectExclusivityAcrossStoreHandles proves the guard is store-level, not pool-level: two independent Store handles on the same file (the multi-process shape) can never both run one project's tasks.

func TestProjectExclusivitySerializesPerProject

func TestProjectExclusivitySerializesPerProject(t *testing.T)

TestProjectExclusivitySerializesPerProject pins the store-level per-repo guarantee: with the option on, a project with a running task yields no further claims (other projects and empty projects unaffected), and the blocked sibling becomes claimable the moment the runner completes. Claim order is priority/created_at/id — not FIFO — so the test never assumes which same-project task goes first.

func TestReclaimFinalizesCancelRequest

func TestReclaimFinalizesCancelRequest(t *testing.T)

TestReclaimFinalizesCancelRequest proves the crashed-worker path: an expired lease on a cancel-requested task finalizes the cancel instead of re-executing the task.

func TestReclaimRecordsUnknownEffectDisposition added in v0.3.4

func TestReclaimRecordsUnknownEffectDisposition(t *testing.T)

TestReclaimRecordsUnknownEffectDisposition pins turnstone's "crashes aren't finishes": reclaiming a lease-expired Running task must record the prior attempt's effect as unknown on the task.released fact, so a re-run is distinguishable from a clean first run. The reclaim observer cannot prove the effect never ran, so it must never stamp the false none.

func TestRecordAnswerOnRunningTaskFactOnly

func TestRecordAnswerOnRunningTaskFactOnly(t *testing.T)

func TestRecordAnswerOnTerminalTaskNeverUnblocks added in v0.4.1

func TestRecordAnswerOnTerminalTaskNeverUnblocks(t *testing.T)

TestRecordAnswerOnTerminalTaskNeverUnblocks pins audit verdict #2 mechanically (2026-10-25 row 1092): an answer recorded for a CANCELLED or DEAD task writes the idempotent question-answered fact (journal truth) but NEVER unblocks or resumes the task — the unblock path is pending-status-only, and resurrecting a terminal task would violate claim exclusivity.

func TestRecordAnswerRawPayloadFactOnly

func TestRecordAnswerRawPayloadFactOnly(t *testing.T)

TestRecordAnswerRawPayloadFactOnly pins fact-only routing for raw (non-object) payloads.

art-dupl:accept conformance scenario prolog: freshStore + parkOnQuestion +; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 RecordAnswer is the parked-question setup, repeated per scenario.

func TestRecordAnswerReplayIsNoop

func TestRecordAnswerReplayIsNoop(t *testing.T)

func TestRecordAnswerSecondQuestionAppends

func TestRecordAnswerSecondQuestionAppends(t *testing.T)

TestRecordAnswerSecondQuestionAppends joins a second question's answer onto the same answered array after the re-claim parks the task again.

art-dupl:accept conformance scenario prolog: freshStore + parkOnQuestion +; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 RecordAnswer is the parked-question setup, repeated per scenario.

func TestRecordAnswerUnblocksParkedTask

func TestRecordAnswerUnblocksParkedTask(t *testing.T)

TestRecordAnswerUnblocksParkedTask answers a parked question and asserts the task re-enters pending with the answered fact recorded.

art-dupl:accept conformance idiom: mutate, Fatalf, re-read via Get; the; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 assertion shape this suite repeats by design.

func TestRecordAnswerValidation

func TestRecordAnswerValidation(t *testing.T)

func TestRequeueDoesNotBurnAttempts

func TestRequeueDoesNotBurnAttempts(t *testing.T)

func TestRequeueFactCarriesClass

func TestRequeueFactCarriesClass(t *testing.T)

TestRequeueFactCarriesClass pins the M9 contract (queue-health restoration): a requeue stamped with a refusal family (preflight, gate, rate-limit, question) carries it as requeue_class in the fact detail, so downstream readers distinguish the environmental classes without re-parsing reason text; an empty class is omitted entirely (omitempty) and read back as RequeueClassUnknown.

art-dupl:accept conformance idiom: action, Fatalf, then FactsForTask; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 fetch; the assertion shape this suite repeats by design.

func TestRequeueFactCarriesProvider added in v0.4.1

func TestRequeueFactCarriesProvider(t *testing.T)

TestRequeueFactCarriesProvider pins the provider-tag contract (04-03 §f8): a rate-limit requeue whose output named the exhausted provider carries it as provider in the fact detail, so the parked surface answers "which provider is limited?" from the journal alone; an empty provider is omitted entirely (omitempty) and reads back as "".

art-dupl:accept conformance idiom: action, Fatalf, then FactsForTask; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 fetch; the assertion shape this suite repeats by design.

func TestRequeueFactCarriesResumeCloseout

func TestRequeueFactCarriesResumeCloseout(t *testing.T)

TestRequeueFactCarriesResumeCloseout pins the 16-00 f31 contract: a closeout-resume requeue stamps resume_closeout into the fact detail so the journal distinguishes an owed close-out turn from a parked work turn; a plain preflight requeue omits the key entirely (omitempty).

func TestRescueDeadEmitsRescueEnqueue

func TestRescueDeadEmitsRescueEnqueue(t *testing.T)

TestRescueDeadEmitsRescueEnqueue pins the rescue-fact wire contract: RescueDead re-emits task.enqueued (NOT task.requeued) with the rescue marker, so a replay treats rescue as a budget reset, not an attempt burn.

art-dupl:accept conformance idiom: action, Fatalf, then FactsForTask; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 fetch; the assertion shape this suite repeats by design.

func TestStatusCountsAndProjectCounts

func TestStatusCountsAndProjectCounts(t *testing.T)

func TestUpdatePendingPriority

func TestUpdatePendingPriority(t *testing.T)

TestUpdatePendingPriority stores a new pending priority, a marker and a reason on a pending task.

art-dupl:accept conformance idiom: mutate, Fatalf, re-read via Get; the; ruling: docs/status/2026-10-05_16-02_art-dupl-t3-tail-zero-dedup-sweep.md a)3 assertion shape this suite repeats by design.

func TestUpdatePendingPriorityFlipsClaimOrder

func TestUpdatePendingPriorityFlipsClaimOrder(t *testing.T)

func TestUpdatePendingPriorityIdempotent

func TestUpdatePendingPriorityIdempotent(t *testing.T)

func TestUpdatePendingPriorityRefusesNonPending

func TestUpdatePendingPriorityRefusesNonPending(t *testing.T)

func TestWatermarkAbsentReturnsZero

func TestWatermarkAbsentReturnsZero(t *testing.T)

func TestWatermarkMonotonicGuard

func TestWatermarkMonotonicGuard(t *testing.T)

func TestWatermarkSaveAndReadRoundtrip

func TestWatermarkSaveAndReadRoundtrip(t *testing.T)

Types

type Caps

type Caps struct {
	// Exclusivity: store-level per-project exclusivity is implemented
	// (WithProjectExclusivity option exists and is honored).
	Exclusivity bool
	// ResumeCloseout: Requeue carries the resume_closeout evidence key.
	ResumeCloseout bool
	// RequeueClass: Requeue carries the requeue_class evidence key.
	RequeueClass bool
	// LegacyMigration: in-place migration from a pre-column/pre-table
	// database file (sqlite-flavored legacy fixtures).
	LegacyMigration bool
	// Archive: the fact archive (facts_archive/journal_meta) exists.
	// False everywhere today — hot-journal-only until upstream grows it.
	Archive bool
	// EnqueuedSnapshot: task.enqueued facts carry the full task snapshot
	// (priority/dedup_key). False everywhere today — upstream enrich,
	// gated on the M4 ratification memo (S1 divergence D2; the engine
	// writes thin {project,type} details). The downstream consumer of
	// this cap is cmd/tq's journal-drift audit — its coverage tests
	// (cmd/tq/journalaudit_test.go) assert the 0-coverage degradation and
	// flip with this Cap.
	EnqueuedSnapshot bool
}

Caps carries the S1 divergences as capabilities: a false Cap skips the matching tests with the divergence reason the backend's suite used to encode inline. Flip a Cap to true when the upstream engine grows the surface — the test bodies are already the contract pins.

type Store

type Store interface {
	AppendFact(ctx context.Context, f journal.Fact) error
	ArchiveFactsBefore(ctx context.Context, cutoff int64) (int64, error)
	ArchiveSummary(ctx context.Context) (companion.ArchiveStats, error)
	Cancel(ctx context.Context, id task.ID, reason string) error
	CancelOwned(ctx context.Context, id task.ID, claim queue.Claim) error
	CancelRequested(ctx context.Context, id task.ID) (bool, error)
	CancelRunning(ctx context.Context, id task.ID, reason string) error
	ClaimCounts(ctx context.Context) (map[string]int, error)
	ClaimDue(ctx context.Context, owner string, lease time.Duration) (task.Task, queue.Claim, error)
	ClaimDueTypes(
		ctx context.Context,
		owner string,
		lease time.Duration,
		types []string,
	) (task.Task, queue.Claim, error)
	Close() error
	Complete(ctx context.Context, id task.ID, claim queue.Claim, result jsontext.Value) error
	CountFacts(ctx context.Context, ftype journal.FactType, since time.Time) (int64, error)
	CountTasks(ctx context.Context, f queue.Filter) (int, error)
	DeletePriorityScores(ctx context.Context, itemKeys []string) (int64, error)
	DismissDead(ctx context.Context, id task.ID, reason, by string) error
	Enqueue(ctx context.Context, n task.New) (task.Task, error)
	Facts(ctx context.Context, after int64, limit int) ([]journal.Fact, error)
	FactsForTask(ctx context.Context, id string, limit int) ([]journal.Fact, error)
	FactsSince(ctx context.Context, ftype journal.FactType, since time.Time, limit int) ([]journal.Fact, error)
	Fail(
		ctx context.Context,
		id task.ID,
		claim queue.Claim,
		errText string,
		backoff time.Duration,
		evidence jsontext.Value,
	) error
	FailPermanent(ctx context.Context, id task.ID, claim queue.Claim, errText string, evidence jsontext.Value) error
	Get(ctx context.Context, id task.ID) (task.Task, error)
	HeadSeq(ctx context.Context) (int64, error)
	Heartbeat(ctx context.Context, id task.ID, claim queue.Claim, extend time.Duration) error
	LastFacts(ctx context.Context, limit int) ([]journal.Fact, error)
	List(ctx context.Context, f queue.Filter) ([]task.Task, error)
	MarkOrphaned(ctx context.Context, cutoff time.Time) (int, error)
	Park(ctx context.Context, id task.ID, reason string, until time.Time, by string) error
	PriorityScore(ctx context.Context, itemKey string) (queue.PriorityScore, bool, error)
	PriorityScores(ctx context.Context) ([]queue.PriorityScore, error)
	ProjectCounts(ctx context.Context) (map[string]map[task.Status]int, error)
	RecordAnswer(ctx context.Context, id task.ID, ans queue.AnswerRecord) error
	Requeue(
		ctx context.Context,
		id task.ID,
		claim queue.Claim,
		errText string,
		delay time.Duration,
		resumeCloseout bool,
		class string,
		provider string,
	) error
	RescueDead(ctx context.Context, id task.ID, maxAttempts int) error
	SavePriorityScore(ctx context.Context, score queue.PriorityScore) error
	SaveWatermark(ctx context.Context, consumer string, seq int64) error
	StatusCounts(ctx context.Context) (map[task.Status]int, error)
	UpdatePendingPriority(ctx context.Context, id task.ID, newPriority int, source, reason string) error
	Watermark(ctx context.Context, consumer string) (int64, bool, error)
}

Store is the exact surface the conformance suite exercises: the queue.Store contract plus the companion extras (facts reads, watermarks, priority scores, questions, archive, project counts). Every spike backend satisfies it.

type Suite

type Suite struct {
	// FreshDSN returns a fresh, isolated database location for one test
	// (sqlite: temp-file path; postgres: per-test schema-scoped dsn with
	// drop-cascade cleanup already registered).
	FreshDSN func(t *testing.T) string
	// OpenOn attaches a Store to dsn and registers its Close via
	// t.Cleanup. opts carries companion store options (exclusivity).
	OpenOn func(t *testing.T, dsn string, opts ...companion.StoreOption) Store
	// Exec runs direct SQL against the store's engine database
	// (test-only seeding/backdating seam, same dialect as production).
	Exec func(ctx context.Context, s Store, query string, args ...any) (sql.Result, error)
	// Begin opens a transaction on the store's engine database (bulk
	// seeding seam).
	Begin func(ctx context.Context, s Store) (*sql.Tx, error)
	// Dialect rewrites the suite's "?"-placeholder SQL for prepared
	// statements inside Begin transactions. Defaults to companion.SQLite.
	Dialect companion.Dialect
	// Caps selects which divergence-gated tests run (see Caps).
	Caps Caps
}

Suite is the backend harness: how to get an isolated database, how to attach stores to it, and how the suite's direct-SQL seams reach the engine. Exec/Begin receive the suite's sqlite-style "?" SQL and apply the dialect themselves (identity for sqlite, pgq for postgres).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL