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 ¶
- func StoreSuite(t *testing.T, s Suite)
- func TestAppendFactDoesNotMaterializeTaskRows(t *testing.T)
- func TestAppendFactRecordsNonTaskFact(t *testing.T)
- func TestArchiveFactsBeforeKeepsProjections(t *testing.T)
- func TestBandFilter(t *testing.T)
- func TestCancelPendingOnly(t *testing.T)
- func TestCancelReasonStoredInFactDetail(t *testing.T)
- func TestCancelRunningRequestAndHonour(t *testing.T)
- func TestClaimAgingAccruesPerWindow(t *testing.T)
- func TestClaimAgingBonusCapped(t *testing.T)
- func TestClaimAgingFlipsOrder(t *testing.T)
- func TestClaimAgingKeyedOnCreatedAtAcrossRequeue(t *testing.T)
- func TestClaimAgingRespectsNotBefore(t *testing.T)
- func TestClaimCountsGroupsPerTask(t *testing.T)
- func TestClaimDueTypesFiltersExecutorTypes(t *testing.T)
- func TestCompleteResetsLastError(t *testing.T)
- func TestCompleteVerifiesLease(t *testing.T)
- func TestCountFactsByTypeSince(t *testing.T)
- func TestCountTasksMatchesList(t *testing.T)
- func TestDepsBlockUntilCompleted(t *testing.T)
- func TestDismissDead(t *testing.T)
- func TestEmptyTypeRejected(t *testing.T)
- func TestEnqueueAndClaim(t *testing.T)
- func TestEnqueueClaimBaseline10k(t *testing.T)
- func TestEnqueueDedupKey(t *testing.T)
- func TestEnqueueFactDetailCarriesIdentity(t *testing.T)
- func TestEnqueueWithoutDedupKeyIndependent(t *testing.T)
- func TestFactsCursorBounded(t *testing.T)
- func TestFactsForTaskFiltersAndBounds(t *testing.T)
- func TestFactsSinceByType(t *testing.T)
- func TestFailPermanentDeadLettersImmediately(t *testing.T)
- func TestFailRetriesThenDeadLetters(t *testing.T)
- func TestFailureEvidenceDetailRoundTrips(t *testing.T)
- func TestGetNotFound(t *testing.T)
- func TestHeadSeq(t *testing.T)
- func TestHeartbeatExtendsLease(t *testing.T)
- func TestLastFactsReturnsTailInAscendingOrder(t *testing.T)
- func TestLeaseExpiryAllowsReclaim(t *testing.T)
- func TestListFilters(t *testing.T)
- func TestListOffsetPagination(t *testing.T)
- func TestListPayloadContains(t *testing.T)
- func TestListQueryLikeEscaping(t *testing.T)
- func TestListQueryPushdown(t *testing.T)
- func TestListSeverityOrder(t *testing.T)
- func TestListSinceFilter(t *testing.T)
- func TestListSortAllowlist(t *testing.T)
- func TestLoadSnapshotScaleAt100k(t *testing.T)
- func TestMarkOrphanedRecordsStrandedTasks(t *testing.T)
- func TestMigrateAddsDedupKeyToOldDatabase(t *testing.T)
- func TestMigrateAddsWatermarksTable(t *testing.T)
- func TestNotBeforeDelays(t *testing.T)
- func TestParkRefusesNonPendingAndUnknown(t *testing.T)
- func TestParkSuppressesClaimsUntilRelease(t *testing.T)
- func TestParkedFilter(t *testing.T)
- func TestParkedRequeueNotResurrectableByStaleLease(t *testing.T)
- func TestPriorityOrdersClaims(t *testing.T)
- func TestPriorityScoreRoundtrip(t *testing.T)
- func TestPriorityScoresListAndDelete(t *testing.T)
- func TestProjectExclusivityAcrossStoreHandles(t *testing.T)
- func TestProjectExclusivitySerializesPerProject(t *testing.T)
- func TestReclaimFinalizesCancelRequest(t *testing.T)
- func TestReclaimRecordsUnknownEffectDisposition(t *testing.T)
- func TestRecordAnswerOnRunningTaskFactOnly(t *testing.T)
- func TestRecordAnswerOnTerminalTaskNeverUnblocks(t *testing.T)
- func TestRecordAnswerRawPayloadFactOnly(t *testing.T)
- func TestRecordAnswerReplayIsNoop(t *testing.T)
- func TestRecordAnswerSecondQuestionAppends(t *testing.T)
- func TestRecordAnswerUnblocksParkedTask(t *testing.T)
- func TestRecordAnswerValidation(t *testing.T)
- func TestRequeueDoesNotBurnAttempts(t *testing.T)
- func TestRequeueFactCarriesClass(t *testing.T)
- func TestRequeueFactCarriesProvider(t *testing.T)
- func TestRequeueFactCarriesResumeCloseout(t *testing.T)
- func TestRescueDeadEmitsRescueEnqueue(t *testing.T)
- func TestStatusCountsAndProjectCounts(t *testing.T)
- func TestUpdatePendingPriority(t *testing.T)
- func TestUpdatePendingPriorityFlipsClaimOrder(t *testing.T)
- func TestUpdatePendingPriorityIdempotent(t *testing.T)
- func TestUpdatePendingPriorityRefusesNonPending(t *testing.T)
- func TestWatermarkAbsentReturnsZero(t *testing.T)
- func TestWatermarkMonotonicGuard(t *testing.T)
- func TestWatermarkSaveAndReadRoundtrip(t *testing.T)
- type Caps
- type Store
- type Suite
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func StoreSuite ¶
StoreSuite runs the full conformance suite against the backend harness.
func TestAppendFactDoesNotMaterializeTaskRows ¶
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 ¶
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 ¶
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 ¶
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 TestCancelReasonStoredInFactDetail ¶
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 ¶
TestCancelRunningRequestAndHonour pins the cooperative-cancel store contract: request (idempotent fact), observation, owner-guarded finalize.
func TestClaimCountsGroupsPerTask ¶ added in v0.4.1
func TestClaimDueTypesFiltersExecutorTypes ¶ added in v0.4.1
func TestCountTasksMatchesList ¶
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 TestDismissDead ¶
func TestEmptyTypeRejected ¶
func TestEnqueueAndClaim ¶
func TestEnqueueClaimBaseline10k ¶
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 TestEnqueueFactDetailCarriesIdentity ¶
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 TestFactsCursorBounded ¶
func TestFactsSinceByType ¶
func TestFailureEvidenceDetailRoundTrips ¶
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 TestHeadSeq ¶
func TestListFilters ¶
func TestListPayloadContains ¶
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 TestListQueryPushdown ¶
func TestListSeverityOrder ¶
func TestListSinceFilter ¶
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 ¶
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 ¶
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 ¶
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 TestNotBeforeDelays ¶
func TestParkRefusesNonPendingAndUnknown ¶ added in v0.4.1
func TestParkSuppressesClaimsUntilRelease ¶ added in v0.4.1
func TestParkedFilter ¶
TestParkedFilter pins the --parked contract: only pending tasks with a future not_before match; completed/pending-due tasks never do.
func TestParkedRequeueNotResurrectableByStaleLease ¶
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 TestPriorityScoresListAndDelete ¶
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 ¶
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 ¶
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 ¶
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
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 TestRecordAnswerOnTerminalTaskNeverUnblocks ¶ added in v0.4.1
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 ¶
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 TestRecordAnswerSecondQuestionAppends ¶
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 ¶
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 TestRequeueFactCarriesClass ¶
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
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 ¶
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 ¶
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 TestUpdatePendingPriority ¶
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.
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).