Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,12 @@ work:
Keep server mode on client-side INSERT batches for Docker-host files;
do not revert to server-side `file()` loading. Preserve shared ClickHouse
SQL behavior while making type conversion explicit for server inserts.
Resolve the nullable-empty-field policy explicitly: prefer preserving
NULL when the benchmark schema permits it, and only use type defaults for
truly non-Nullable columns when that matches the source semantics.
Implement the ratified nullable-empty-field policy (see open_questions
below): an empty numeric/date value becomes NULL with Nullable(T) DDL
where the reference schema marks the column nullable; NEVER coerce to a
type default. An empty landing in a column the reference schema marks
NOT NULL must fail loudly as a benchmark data defect, not be silently
defaulted.

DONE (Buckets B + C): _convert_field_for_clickhouse now classifies
DATETIME/DateTime64/TIMESTAMP before the DATE prefix and parses to Python
Expand Down Expand Up @@ -151,6 +154,7 @@ deferred:
deps:
needs:
- uat-clickhouse-server-rc1-recovery
- uat-clickhouse-loader-empty-value-nullability

must_preserve:
- "Keep the PR #738 server-mode contract: Docker-host data files load through client-side batches, not server-side `file()` paths."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ verification:

scope_limit:
only_modify:
- "tests/uat/throughput.py"
- "benchbox/core/tpch/"
- "benchbox/core/expected_results/"
- "benchbox/core/validation/"
- "tests/unit/core/"
- "tests/uat/test_throughput.py"

metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ work:
must_preserve), and delete the mtime-window logic. Keep a loud failure if
the path is absent rather than silently falling back to glob.

Handoff: tests/uat/runner.py's `official` branch (currently ~line 241-251)
calls resolve_official_result_path directly and does not pass or parse
`stdout_text` at all -- only the non-official `else` branch does
(last_nonempty_output_line(stdout_text)). If w1 picks the quiet-stdout-line
contract, runner.py's official branch must be updated to read that line the
same way the non-official branch already does; if w1 picks a manifest file,
runner.py must locate/pass it instead. Either way runner.py's official
branch changes, so it (and test_runner.py) must be in scope, not just the
resolver + CLI.

deferred:
- summary: "Backfill emitted-path contract to other non-quiet producers if any remain"
reason: "Scope here is the official/throughput path; a broader producer audit is separate."
Expand Down Expand Up @@ -88,6 +98,8 @@ scope_limit:
only_modify:
- "tests/uat/throughput.py"
- "tests/uat/test_throughput.py"
- "tests/uat/runner.py"
- "tests/uat/test_runner.py"
- "benchbox/cli/ (run-official output contract)"
- "docs/reference/public-contracts.md"

Expand Down
4 changes: 2 additions & 2 deletions _project/config/fast_test_lane_policy.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"enabled": true,
"max_fast_tests": 25190,
"_ceiling_note": "Bumped 13200 -> 22000 on 2026-04-13 to reflect grown fast-lane (20,184 collected). Bumped 22000 -> 22100 on 2026-05-10 for joinorder-canonical-foundation Phase-1 (data_fetch + scale-factor + surface-field tests; 22038 collected). Bumped 22100 -> 22400 on 2026-05-11 for joinorder-canonical-cutover canonical SQL/DataFrame, MCP, publishing, and corpus-inventory guards; 22317 collected. Bumped 22400 -> 22500 on 2026-05-13 for UAT enabled-platform remediation coverage; pr-preflight collected 22419. Bumped 22500 -> 22510 on 2026-05-15 after rebasing onto develop at 36ab01058; pr-preflight collected 22501 before this branch's new public theme contract tests, which are medium-marked to avoid fast-lane growth. Bumped 22510 -> 22530 on 2026-05-14 for pr-review-followup batch coverage (joinorder dataframe family, pg_mooncake adapter, landing quickstart validation, explorer read-model retry); pr-preflight collected 22520. Bumped 22530 -> 22540 on 2026-05-15 for results-explorer-post-theme-reconcile count-aware Home/script coverage; CI collected 22537. Bumped 22540 -> 22543 on 2026-05-16 for pr-review-followups coverage on UAT CLI dispatch, UAT release-gate envelope scoping, and develop-post-merge orphan ordering; ci-lint collected 22543. Bumped 22543 -> 22550 on 2026-05-16 for prompts landing Phase 1 CLI hygiene validator/prompt-shape coverage; pr-preflight collected 22550. Bumped 22550 -> 22553 on 2026-05-16 for prompts landing Phase 2 cost-class and registry prompt-safety coverage; timing policy collected 22553. Bumped 22553 -> 22558 on 2026-05-16 for prompts landing Phase 3 platform-option and TPC-DS dsdgen validator coverage; timing_policy_check collected 22558. Bumped 22558 -> 22561 on 2026-05-16 for prompts landing Phase 4 provenance template and capture-plan footer coverage; timing_policy_check collected 22561. Bumped 22561 -> 22563 on 2026-05-16 for prompts landing review fixes covering MCP cost-gating parity and compare summary discipline; targeted lane count increased by two fast tests. Bumped 22563 -> 22568 on 2026-05-16 for prompts landing Phase 5 MCP parity prompt-surface coverage; timing_policy_check collected 22568. Bumped 22568 -> 22570 on 2026-05-16 for prompts landing MCP real-tool parity and platform-option gap follow-up coverage; timing_policy_check collected 22570. Bumped 22570 -> 22572 on 2026-05-19 for pr-review-followups prompt regressions covering credential-before-smoke ordering and smoke-scale dsdgen warning behavior; timing_policy_check collected 22572. Set 22572 -> 25000 on 2026-05-19 by maintainer direction during pr-review-followups cleanup. Ratchet down if the lane contracts; never raise without justification. Bumped 25000 -> 25050 on 2026-07-16 for tuning-mode-vocabulary-and-facet-implementation-20260712 (ADR-2 canonical_mode/tuned-fallback/official-refusal coverage, the PACKAGED_RESOURCE composition pin added when merging develop's #1188 packaged-template tier, and the physical_mechanisms unknown-vs-empty ingest-pipeline regression tests); develop alone collected 24995, this branch's merge collected 25022. Bumped 25050 -> 25060 on 2026-07-17 for tuning-capability-registry-coverage-20260716 (alias-resolution invariant tests and derived generator-coverage drift guards for the 9 newly-registered platforms); CI collected 25052 on the merge ref. Bumped 25060 -> 25080 on 2026-07-17 composing #1198's registry-coverage guards with #1176's provenance/hash export coverage (test_tuning_provenance_export.py + test_requested_config_hash.py); both branches independently bumped from 25050 (#1198: 25052 collected; #1176 pre-compose: 25062 collected); composed merge tree collects 25077. Bumped 25080 -> 25140 on 2026-07-17 for tuning-from-config-forwarding-sweep-20260716 (test_tuning_config_forwarding.py's registry-driven parametrized test, one case per registered platform adapter, verifying from_config forwards tuning_enabled/tuning_config/unified_tuning_configuration/tuning_source/tuning_source_file); timing_policy_check collected 25128. Bumped 25140 -> 25180 on 2026-07-18 for the todo-db-tracker local-SQLite spike (tests/unit/scripts/test_todo_db.py: 49 fast unit tests covering the enforced lifecycle invariants, archive import, and concurrency guards); develop collected 25128, this branch collects 25177. Bumped 25180 -> 25190 on 2026-07-18 composing the todo-db spike branch with develop's post-25128 growth: the branch alone collects 25177 (49 fast tracker tests; the 11 wrapper tests are medium-marked and collect 0 under -m fast), but the PR merge ref collects 25187.",
"max_fast_tests": 25220,
"_ceiling_note": "Bumped 13200 -> 22000 on 2026-04-13 to reflect grown fast-lane (20,184 collected). Bumped 22000 -> 22100 on 2026-05-10 for joinorder-canonical-foundation Phase-1 (data_fetch + scale-factor + surface-field tests; 22038 collected). Bumped 22100 -> 22400 on 2026-05-11 for joinorder-canonical-cutover canonical SQL/DataFrame, MCP, publishing, and corpus-inventory guards; 22317 collected. Bumped 22400 -> 22500 on 2026-05-13 for UAT enabled-platform remediation coverage; pr-preflight collected 22419. Bumped 22500 -> 22510 on 2026-05-15 after rebasing onto develop at 36ab01058; pr-preflight collected 22501 before this branch's new public theme contract tests, which are medium-marked to avoid fast-lane growth. Bumped 22510 -> 22530 on 2026-05-14 for pr-review-followup batch coverage (joinorder dataframe family, pg_mooncake adapter, landing quickstart validation, explorer read-model retry); pr-preflight collected 22520. Bumped 22530 -> 22540 on 2026-05-15 for results-explorer-post-theme-reconcile count-aware Home/script coverage; CI collected 22537. Bumped 22540 -> 22543 on 2026-05-16 for pr-review-followups coverage on UAT CLI dispatch, UAT release-gate envelope scoping, and develop-post-merge orphan ordering; ci-lint collected 22543. Bumped 22543 -> 22550 on 2026-05-16 for prompts landing Phase 1 CLI hygiene validator/prompt-shape coverage; pr-preflight collected 22550. Bumped 22550 -> 22553 on 2026-05-16 for prompts landing Phase 2 cost-class and registry prompt-safety coverage; timing policy collected 22553. Bumped 22553 -> 22558 on 2026-05-16 for prompts landing Phase 3 platform-option and TPC-DS dsdgen validator coverage; timing_policy_check collected 22558. Bumped 22558 -> 22561 on 2026-05-16 for prompts landing Phase 4 provenance template and capture-plan footer coverage; timing_policy_check collected 22561. Bumped 22561 -> 22563 on 2026-05-16 for prompts landing review fixes covering MCP cost-gating parity and compare summary discipline; targeted lane count increased by two fast tests. Bumped 22563 -> 22568 on 2026-05-16 for prompts landing Phase 5 MCP parity prompt-surface coverage; timing_policy_check collected 22568. Bumped 22568 -> 22570 on 2026-05-16 for prompts landing MCP real-tool parity and platform-option gap follow-up coverage; timing_policy_check collected 22570. Bumped 22570 -> 22572 on 2026-05-19 for pr-review-followups prompt regressions covering credential-before-smoke ordering and smoke-scale dsdgen warning behavior; timing_policy_check collected 22572. Set 22572 -> 25000 on 2026-05-19 by maintainer direction during pr-review-followups cleanup. Ratchet down if the lane contracts; never raise without justification. Bumped 25000 -> 25050 on 2026-07-16 for tuning-mode-vocabulary-and-facet-implementation-20260712 (ADR-2 canonical_mode/tuned-fallback/official-refusal coverage, the PACKAGED_RESOURCE composition pin added when merging develop's #1188 packaged-template tier, and the physical_mechanisms unknown-vs-empty ingest-pipeline regression tests); develop alone collected 24995, this branch's merge collected 25022. Bumped 25050 -> 25060 on 2026-07-17 for tuning-capability-registry-coverage-20260716 (alias-resolution invariant tests and derived generator-coverage drift guards for the 9 newly-registered platforms); CI collected 25052 on the merge ref. Bumped 25060 -> 25080 on 2026-07-17 composing #1198's registry-coverage guards with #1176's provenance/hash export coverage (test_tuning_provenance_export.py + test_requested_config_hash.py); both branches independently bumped from 25050 (#1198: 25052 collected; #1176 pre-compose: 25062 collected); composed merge tree collects 25077. Bumped 25080 -> 25140 on 2026-07-17 for tuning-from-config-forwarding-sweep-20260716 (test_tuning_config_forwarding.py's registry-driven parametrized test, one case per registered platform adapter, verifying from_config forwards tuning_enabled/tuning_config/unified_tuning_configuration/tuning_source/tuning_source_file); timing_policy_check collected 25128. Bumped 25140 -> 25180 on 2026-07-18 for the todo-db-tracker local-SQLite spike (tests/unit/scripts/test_todo_db.py: 49 fast unit tests covering the enforced lifecycle invariants, archive import, and concurrency guards); develop collected 25128, this branch collects 25177. Bumped 25180 -> 25190 on 2026-07-18 composing the todo-db spike branch with develop's post-25128 growth: the branch alone collects 25177 (49 fast tracker tests; the 11 wrapper tests are medium-marked and collect 0 under -m fast), but the PR merge ref collects 25187. Bumped 25190 -> 25220 on 2026-07-18 for the post-CODEOWNERS-retirement merge queue, composed once so the queued branches carry byte-identical policy content instead of five conflicting bumps (#1142 seed-validation exclusion coverage +10; #1116 bot-finding sweep regressions +4; #1202 capability-registry/report regressions ~+8; #1206 object-schema loader regressions ~+5; #1114 branch-rename test moves +0): develop alone collects 25187; the queue's final merge ref is expected to collect ~25214.",
"forbidden_marker_expressions": [
"resource_heavy",
"stress",
Expand Down
11 changes: 11 additions & 0 deletions benchbox/core/tuning/capability_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,17 @@ def _constraint_entries() -> dict[TuningType, TuningCapability]:
"PgDuckDBAdapter never runs any post_create_statements via the inherited no-op "
"apply_table_tunings/generate_tuning_clause path.",
),
_T.SORTING: _none(
"pg_duckdb_inherited_postgresql_noop",
"PostgreSQLDDLGenerator treats SORTING as CLUSTERING -- a shared code path (postgresql.py:"
"141-159) appends both a CREATE INDEX and a CLUSTER post_create_statement for either tuning "
"type. PgDuckDBDDLGenerator's inherited generate_tuning_clauses runs that same path before its "
"filter (pg_duckdb.py:83-88) strips only the CLUSTER statement by prefix match, so a tuned "
"SORTING config's CREATE INDEX still surfaces in dry-run preview, same as CLUSTERING. Same "
"execution-time no-op as CLUSTERING/PARTITIONING regardless: PgDuckDBAdapter never runs "
"post_create_statements via the inherited no-op apply_table_tunings/generate_tuning_clause "
"path.",
),
},
"pg-mooncake": {
_T.PARTITIONING: _none(
Expand Down
11 changes: 9 additions & 2 deletions tests/uat/phases/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,12 +870,19 @@ def _docker_result_message(result: docker_assets.DockerCommandResult) -> str:


def append_lifecycle_log(log_dir: Path | None, line: str) -> None:
"""Append a timestamped line to uat_lifecycle.log. Public: also called from orchestrator.py (sweep-start engine identity, uat-container-engine-routing w2)."""
"""Append a timestamped line to uat_lifecycle.log. Public: also called from orchestrator.py (sweep-start engine identity, uat-container-engine-routing w2).

The timestamp is offset-aware (``datetime.now().astimezone()``, not plain
``datetime.now()``) so a release-gate boundary comparison spanning a DST
transition (see report.py's ``release_gate_ordering_violations``) can use
each event's own recorded offset instead of having to assume one (#1179,
#1202 follow-up).
"""
if log_dir is None:
return
log_dir.mkdir(parents=True, exist_ok=True)
with (log_dir / "uat_lifecycle.log").open("a", encoding="utf-8") as fh:
fh.write(f"{_dt.datetime.now().isoformat(timespec='seconds')} {line}\n")
fh.write(f"{_dt.datetime.now().astimezone().isoformat(timespec='seconds')} {line}\n")


def default_log_dir(config: UATConfig, now: _dt.datetime | None = None) -> Path:
Expand Down
23 changes: 14 additions & 9 deletions tests/uat/phases/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,16 +426,21 @@ def release_gate_ordering_violations(
violations: list[str] = []
for log_text in docker_stage_lifecycle_logs:
for timestamp, platform in parse_docker_up_events(log_text):
# append_lifecycle_log() writes datetime.now() (naive local
# wall-clock time, no offset), but native_stage_completed_at is
# offset-aware in production (orchestrator.py's
# datetime.now().astimezone(), #1162). Comparing a naive and an
# aware datetime raises TypeError, so normalize a naive
# timestamp onto native_stage_completed_at's awareness -- via
# astimezone(), which interprets a naive datetime as local time
# and attaches the current local UTC offset -- before comparing.
# append_lifecycle_log() now writes offset-aware timestamps
# (datetime.now().astimezone(), #1202 follow-up) so each Docker
# event carries its own real offset -- correct even across a DST
# transition mid-sweep. This branch is a best-effort fallback for
# uat_lifecycle.log files written by an older BenchBox version
# that recorded naive local wall-clock time with no offset at
# all: attach the boundary's own offset, since both timestamps
# come from the same host/sweep run and no better information is
# available for a legacy naive entry (#1179). A stale log mixing
# naive pre-upgrade lines with a DST transition can still
# misattribute the offset -- there is no way to recover the true
# offset of a naive timestamp after the fact; only fresh
# offset-aware logs are exact.
if timestamp.tzinfo is None and native_stage_completed_at.tzinfo is not None:
timestamp = timestamp.astimezone()
timestamp = timestamp.replace(tzinfo=native_stage_completed_at.tzinfo)
Comment thread
joeharris76 marked this conversation as resolved.
if timestamp <= native_stage_completed_at:
violations.append(
f"Docker stack '{platform}' started at {timestamp.isoformat()} "
Expand Down
Loading
Loading