diff --git a/.ddx/beads.jsonl b/.ddx/beads.jsonl index 11c5b2d..272ffac 100644 --- a/.ddx/beads.jsonl +++ b/.ddx/beads.jsonl @@ -27,7 +27,7 @@ {"acceptance":"At least one test for missing warehouse or unreachable location with actionable message.","closing_commit_sha":"6857ad0da3e8839e3fb40c6fe806ee7f4060e562","created_at":"2026-07-22T21:41:07.232277639Z","dependencies":[{"issue_id":"tablespec-0e6cd069","depends_on_id":"tablespec-2a68a0ad","type":"blocks","created_at":"2026-07-22T21:41:07Z"}],"description":"Missing or unusable configuration surfaces one actionable startup error naming setting and grant.","events_attachment":"tablespec-0e6cd069/events.jsonl","id":"tablespec-0e6cd069","issue_type":"task","labels":["helix","phase:build","area:app","FEAT-034"],"notes":"[2026-07-22T22:02:15Z] closure rejected: closure gate: insufficient evidence: no execution evidence (empty events and no closing_commit_sha)","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"App: startup fail-fast configuration validation (FR-23.6 / US-049)","updated_at":"2026-07-22T22:03:01.262348031Z"} {"acceptance":"1. TestDatabricksDocsUseCanonicalDialectGuidance: add a docs traceability test that scans docs/guide/bootstrap.md, README.md, Databricks notebook/try-it-out docs, and selected docs/helix files to verify they state dialect=\"databricks\" is accepted for Databricks compile UX and explain that casts render as Spark-family SQL.\n2. TestCliHelpExplainsDatabricksAlias: add a Typer CLI help test proving --dialect help names duckdb, spark, databricks and includes the Spark-family alias relationship or points to consistent accepted values.\n3. TestNoPublicDocsContradictDatabricksAlias: assert public docs no longer say Databricks users must use only dialect=\"spark\" unless the sentence explicitly explains internal Spark-family normalization.\n4. Test gates: uv run pytest tests/unit/test_api_docs_traceability.py tests/unit/test_cli_domains_set.py; go test ./...; lefthook run pre-commit.","created_at":"2026-06-08T01:04:03.709588757Z","description":"PROBLEM: Public instructions are inconsistent. The CLI advertises databricks as a cast dialect, Databricks conformance docs discuss dialect=\"databricks\", but bootstrap docs show dialect=\"spark\" or omit the relationship, leaving users unsure which spelling is correct.\nROOT CAUSE: src/tablespec/cli.py:525 says \"duckdb, spark, databricks\" without explaining Spark-family normalization. docs/guide/bootstrap.md:18 tells Databricks/Spark bootstrap users to pass dialect=\"spark\". README.md:144-149 shows bootstrap_from_tables without a dialect. docs/helix/03-test/conformance-acceptance.md:85 and docs/helix/03-test/conformance-acceptance.md:109 already describe databricks dialect behavior, but that decision is not reflected consistently in user-facing bootstrap/try-it-out docs.\nPROPOSED FIX: Update CLI help, docs/guide/bootstrap.md, README.md, Databricks notebook/try-it-out docs, and relevant docs/helix references to one canonical instruction: public Databricks compile UX accepts dialect=\"databricks\" as an explicit alias for Spark-family cast SQL, and internal emitters may normalize to spark when SQL is identical. Align all examples and error-message wording with that decision.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No broad documentation rewrite outside Databricks dialect guidance.\nGOVERNING ARTIFACTS: docs/guide/bootstrap.md:10; README.md:139; docs/helix/03-test/conformance-acceptance.md:109; scripts/run_integration_tests_databricks.ipynb.\nDEPENDENCIES: none inherited from parent.\nVERIFICATION: Add docs/CLI tests and run uv/pytest, go test, and lefthook gates.","events_attachment":"tablespec-0fb0d1c2/events.jsonl","execution-eligible":false,"id":"tablespec-0fb0d1c2","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-ed74497c","priority":0,"schema_version":1,"status":"closed","title":"Canonicalize Databricks dialect guidance in CLI help and docs","updated_at":"2026-06-08T20:18:39.059178973Z"} {"acceptance":"Test with optional keys unset: app starts; optional UI sections absent.","closing_commit_sha":"6857ad0da3e8839e3fb40c6fe806ee7f4060e562","created_at":"2026-07-22T21:41:07.325508086Z","description":"Unset dashboard/Genie/UMF volume hides dependent surfaces rather than erroring.","events_attachment":"tablespec-112c6f19/events.jsonl","id":"tablespec-112c6f19","issue_type":"task","labels":["helix","phase:build","area:app","FEAT-034"],"notes":"[2026-07-22T22:02:15Z] closure rejected: closure gate: insufficient evidence: no execution evidence (empty events and no closing_commit_sha)","owner":"erik","parent":"tablespec-263a0248","priority":2,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"App: optional integrations degrade cleanly (FR-23.5)","updated_at":"2026-07-22T22:03:02.828042332Z"} -{"acceptance":"1. TestCompileUmfsAcceptsDatabricksDialect: add a compile-path test proving compile_umfs(..., dialect=\"databricks\") completes without ValueError and persists ingest, dbt_ingest, optional dbt_gold, LDP, and manifest artifacts under the pinned layout.\n2. TestGenerateLdpProjectAcceptsDatabricksAlias: add an LDP unit/conformance test proving generate_ldp_project(..., dialect=\"databricks\") succeeds and emits the same Spark-family cast body as dialect=\"spark\".\n3. TestDatabricksCompileArtifactsStateNormalizationDecision: assert the implementation notes or generated metadata/comments state the decision: public dialect=\"databricks\" is accepted and Spark-family SQL emitters may normalize to spark internally because cast SQL is identical.\n4. Test gates: uv run pytest tests/unit/test_bootstrap.py tests/e2e/test_bootstrap_from_specs.py tests/ldp/test_ldp_emitter.py tests/ldp/test_ldp_cast_parity.py; go test ./...; lefthook run pre-commit.","created_at":"2026-06-08T01:04:03.685235027Z","description":"PROBLEM: The documented compile/bootstrap path can receive dialect=databricks, but not every emitted artifact path proves that spelling end-to-end. Some compile seams hard-code spark or document only spark/duckdb, so a downstream validator can still reject databricks or silently bypass the requested dialect.\nROOT CAUSE: src/tablespec/e2e/compile.py:129 forwards the caller dialect to generate_dbt_dag_project, but src/tablespec/e2e/compile.py:141 hard-codes generate_ldp_project(..., dialect=\"spark\"). src/tablespec/e2e/compile.py:193 calls generate_ingest_sql without a dialect, and src/tablespec/schemas/ingest_generator.py:214 hard-codes build_ingest_select(..., dialect=\"spark\"). src/tablespec/ldp/project.py:242 documents LDP dialect as Spark with duckdb accepted for parity, but omits databricks even though LDP runs on Databricks.\nPROPOSED FIX: Make compile_umfs accept dialect=\"databricks\" across all relevant compile seams. Preserve dbt target behavior as databricks, and normalize Spark-family SQL emitters internally where SQL is identical. Either add a dialect argument to generate_ingest_sql or explicitly document/direct-test that direct ingest artifacts are Spark-family and stable under databricks compile. Update LDP generation to accept databricks as an alias for Spark-family casts.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers.\nGOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109.\nDEPENDENCIES: none inherited from parent.\nVERIFICATION: Add compile/emitter tests and run uv/pytest, go test, and lefthook gates.","events":[{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"readiness route unavailable: lifecycle dispatch: snapshot project root dirtiness: exit status 128\",\"fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\",\"policy_mode\":\"warn-only\",\"reason\":\"system_unready\",\"rule_id\":\"pre_claim_intake.system_unready\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\"}","created_at":"2026-06-08T01:58:10.980939598Z","kind":"intake.warn","source":"ddx work","summary":"system_unready"},{"actor":"ddx","body":"{\"actual_harness\":\"\",\"actual_model\":\"\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"\",\"bead_id\":\"tablespec-171e409c\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"\",\"routing_intent_degraded\":true,\"routing_intent_note\":\"actual route facts unavailable\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T01:58:11.481417322Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard note=actual route facts unavailable"},{"actor":"erik","body":"{\"base_rev\":\"\",\"classification\":\"recoverable\",\"detail\":\"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\",\"rationale\":\"The attempt failed before implementation during the pre-execute checkpoint while listing worktree/checkpoint dirtiness with git exit status 128. Recent intake evidence also reports system_unready from project root dirtiness snapshot failure, so this is infrastructure/preflight failure rather than a bead defect or code regression.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"\",\"session_id\":\"\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T01:58:41.59268296Z","kind":"bead-quality.triage","source":"ddx work","summary":"recoverable: release_claim_retry"},{"actor":"erik","body":"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\noutcome_reason=recoverable","created_at":"2026-06-08T01:58:41.620854787Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"readiness route unavailable: lifecycle dispatch: snapshot project root dirtiness: exit status 128\",\"fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\",\"policy_mode\":\"warn-only\",\"reason\":\"system_unready\",\"rule_id\":\"pre_claim_intake.system_unready\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\"}","created_at":"2026-06-08T02:02:40.533739039Z","kind":"intake.warn","source":"ddx work","summary":"system_unready"},{"actor":"ddx","body":"{\"actual_harness\":\"\",\"actual_model\":\"\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"\",\"bead_id\":\"tablespec-171e409c\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"\",\"routing_intent_degraded\":true,\"routing_intent_note\":\"actual route facts unavailable\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T02:02:40.925914769Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard note=actual route facts unavailable"},{"actor":"erik","body":"{\"base_rev\":\"\",\"classification\":\"transport\",\"detail\":\"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\",\"rationale\":\"The bead failed during the pre-execute checkpoint with 'listing checkpoint dirt: exit status 128', which indicates a transient infrastructure/git state issue rather than a problem with the bead specification or code implementation. Recent intake events also report system_unready from project root dirtiness snapshot failure, confirming this is a transport/preflight failure. The bead quality triage already classified this as recoverable with release_claim_retry.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"\",\"session_id\":\"\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T02:02:55.960124675Z","kind":"bead-quality.triage","source":"ddx work","summary":"transport: release_claim_retry"},{"actor":"erik","body":"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\noutcome_reason=transport","created_at":"2026-06-08T02:02:55.986844748Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"readiness route unavailable: lifecycle dispatch: snapshot project root dirtiness: exit status 128\",\"fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\",\"policy_mode\":\"warn-only\",\"reason\":\"system_unready\",\"rule_id\":\"pre_claim_intake.system_unready\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\"}","created_at":"2026-06-08T02:05:39.013526634Z","kind":"intake.warn","source":"ddx work","summary":"system_unready"},{"actor":"ddx","body":"{\"actual_harness\":\"\",\"actual_model\":\"\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"\",\"bead_id\":\"tablespec-171e409c\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"\",\"routing_intent_degraded\":true,\"routing_intent_note\":\"actual route facts unavailable\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T02:05:39.402200949Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard note=actual route facts unavailable"},{"actor":"erik","body":"{\"base_rev\":\"\",\"classification\":\"transport\",\"detail\":\"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\",\"rationale\":\"The attempt failed before implementation during the pre-execute checkpoint while listing checkpoint dirtiness with git exit status 128. Recent events repeatedly show project-root dirtiness snapshot failure/system_unready, so the narrow cause is a transport/preflight infrastructure failure rather than a bead defect, implementation regression, or external blocker.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"\",\"session_id\":\"\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T02:05:57.526300135Z","kind":"bead-quality.triage","source":"ddx work","summary":"transport: release_claim_retry"},{"actor":"erik","body":"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\noutcome_reason=transport","created_at":"2026-06-08T02:05:57.551086Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"system_unready: This is a single docs/CLI guidance task already split out from the broader Databricks dialect parent. The acceptance criteria are coherent and locally testable, the scope stays inside user-facing docs/help plus traceability tests, and the prior failures are transport/preflight noise rather than a specification blocker.\",\"fingerprint\":\"7a5c99fdc017101fd5cf4f50e8cfca4d003d6ef65585a9b8e791eed1f63e8cce\",\"policy_mode\":\"warn-only\",\"reason\":\"system_unready\",\"rule_id\":\"pre_claim_intake.system_unready\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"7a5c99fdc017101fd5cf4f50e8cfca4d003d6ef65585a9b8e791eed1f63e8cce\"}","created_at":"2026-06-08T06:49:55.960658623Z","kind":"intake.warn","source":"ddx work","summary":"system_unready"},{"actor":"ddx","body":"{\"resolved_provider\":\"codex\",\"resolved_model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"fallback_chain\":[]}","created_at":"2026-06-08T07:31:38.222311385Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=codex model=gpt-5.4-mini reason=explicit_pin_discovery_unavailable"},{"actor":"ddx","body":"{\"actual_harness\":\"\",\"actual_model\":\"\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"\",\"bead_id\":\"tablespec-171e409c\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"\",\"routing_intent_degraded\":true,\"routing_intent_note\":\"actual route facts unavailable\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T07:31:48.555302669Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard note=actual route facts unavailable"},{"actor":"erik","body":"{\"base_rev\":\"\",\"classification\":\"recoverable\",\"detail\":\"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\",\"rationale\":\"The attempt failed before implementation during the pre-execute checkpoint while listing checkpoint dirtiness with git exit status 128. The evidence points to a repository/preflight infrastructure failure, not a bead defect, code regression, external blocker, or verification failure.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"\",\"session_id\":\"\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T07:32:29.424327714Z","kind":"bead-quality.triage","source":"ddx work","summary":"recoverable: release_claim_retry"},{"actor":"erik","body":"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\noutcome_reason=recoverable","created_at":"2026-06-08T07:32:29.474566211Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"readiness route unavailable: lifecycle dispatch: snapshot project root dirtiness: exit status 128\",\"fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\",\"policy_mode\":\"warn-only\",\"reason\":\"system_unready\",\"rule_id\":\"pre_claim_intake.system_unready\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"65124584ad3f1c6e5900c0aafa8ce291c4e983f47acc8269b667040304b48266\"}","created_at":"2026-06-08T07:32:31.656628774Z","kind":"intake.warn","source":"ddx work","summary":"system_unready"},{"actor":"ddx","body":"{\"actual_harness\":\"\",\"actual_model\":\"\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"\",\"bead_id\":\"tablespec-171e409c\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"\",\"routing_intent_degraded\":true,\"routing_intent_note\":\"actual route facts unavailable\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T07:34:34.721706915Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard note=actual route facts unavailable"},{"actor":"erik","body":"{\"base_rev\":\"\",\"classification\":\"recoverable\",\"detail\":\"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\",\"rationale\":\"The attempt failed before implementation during the pre-execute checkpoint while listing checkpoint dirtiness with git exit status 128. This is repository/preflight infrastructure failure evidence, not a bead defect, code regression, external blocker, or verification failure; the same failure pattern was already triaged as recoverable.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"\",\"session_id\":\"\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T07:34:58.21981555Z","kind":"bead-quality.triage","source":"ddx work","summary":"recoverable: release_claim_retry"},{"actor":"erik","body":"pre-execute-bead checkpoint: listing checkpoint dirt: exit status 128\noutcome_reason=recoverable","created_at":"2026-06-08T07:34:58.237998617Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"ac_map\":[{\"parent_ac\":\"1. TestCompileUmfsAcceptsDatabricksDialect: add a compile-path test proving compile_umfs(..., dialect=\\\"databricks\\\") completes without ValueError and persists ingest, dbt_ingest, optional dbt_gold, LDP, and manifest artifacts under the pinned layout.\",\"coverage\":\"Child 1 AC1 TestCompileUmfsAcceptsDatabricksDialect; Child 1 AC2 TestCompileUmfsPreservesPublicDialectInManifest\"},{\"parent_ac\":\"2. TestGenerateLdpProjectAcceptsDatabricksAlias: add an LDP unit/conformance test proving generate_ldp_project(..., dialect=\\\"databricks\\\") succeeds and emits the same Spark-family cast body as dialect=\\\"spark\\\".\",\"coverage\":\"Child 2 AC1 TestGenerateLdpProjectAcceptsDatabricksAlias; Child 2 AC2 TestGenerateLdpProjectSparkParityRemainsStable\"},{\"parent_ac\":\"3. TestDatabricksCompileArtifactsStateNormalizationDecision: assert the implementation notes or generated metadata/comments state the decision: public dialect=\\\"databricks\\\" is accepted and Spark-family SQL emitters may normalize to spark internally because cast SQL is identical.\",\"coverage\":\"Child 3 AC1 TestDatabricksCompileArtifactsStateNormalizationDecision; Child 3 AC2 TestDatabricksDialectContractIsDocumented\"},{\"parent_ac\":\"4. Test gates: uv run pytest tests/unit/test_bootstrap.py tests/e2e/test_bootstrap_from_specs.py tests/ldp/test_ldp_emitter.py tests/ldp/test_ldp_cast_parity.py; go test ./...; lefthook run pre-commit.\",\"coverage\":\"Child 1 AC3 TestPytestGate; Child 1 AC4 TestGoGate; Child 1 AC5 TestLefthookGate; Child 2 AC3 TestPytestGate; Child 2 AC4 TestGoGate; Child 2 AC5 TestLefthookGate; Child 3 AC3 TestPytestGate; Child 3 AC4 TestGoGate; Child 3 AC5 TestLefthookGate\"}],\"child_ids\":[\"tablespec-924c7384\",\"tablespec-bc47a14e\",\"tablespec-943b21a5\"],\"rationale\":\"Split the bead into three independently executable slices: compile-path normalization, direct LDP aliasing, and contract documentation. This preserves the governing artifacts, dependency identity, and required verification while reducing overlap between code changes and letting each child close with targeted tests plus the shared go/lefthook gates.\"}","created_at":"2026-06-08T14:50:25.00456072Z","kind":"triage-decomposed","source":"ddx work","summary":"decomposed into tablespec-924c7384, tablespec-bc47a14e, tablespec-943b21a5"}],"execution-eligible":false,"id":"tablespec-171e409c","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-ed74497c","priority":0,"schema_version":1,"status":"open","title":"Thread dialect=databricks through compile and LDP emitter paths","updated_at":"2026-06-08T14:50:25.19072127Z"} +{"acceptance":"1. compile_umfs(..., dialect=\"databricks\") succeeds (test_compile_umfs_accepts_databricks_dialect).\n2. generate_ldp_project accepts databricks (test_generate_ldp_project_accepts_databricks_alias).\n3. Spark/databricks LDP payloads identical.\n4. Pytest gates above. (No Go gate.)","created_at":"2026-06-08T01:04:03.685235027Z","description":"PROBLEM: The documented compile/bootstrap path can receive dialect=databricks, but not every emitted artifact path proves that spelling end-to-end. Some compile seams hard-code spark or document only spark/duckdb, so a downstream validator can still reject databricks or silently bypass the requested dialect.\nROOT CAUSE: src/tablespec/e2e/compile.py:129 forwards the caller dialect to generate_dbt_dag_project, but src/tablespec/e2e/compile.py:141 hard-codes generate_ldp_project(..., dialect=\"spark\"). src/tablespec/e2e/compile.py:193 calls generate_ingest_sql without a dialect, and src/tablespec/schemas/ingest_generator.py:214 hard-codes build_ingest_select(..., dialect=\"spark\"). src/tablespec/ldp/project.py:242 documents LDP dialect as Spark with duckdb accepted for parity, but omits databricks even though LDP runs on Databricks.\nPROPOSED FIX: Make compile_umfs accept dialect=\"databricks\" across all relevant compile seams. Preserve dbt target behavior as databricks, and normalize Spark-family SQL emitters internally where SQL is identical. Either add a dialect argument to generate_ingest_sql or explicitly document/direct-test that direct ingest artifacts are Spark-family and stable under databricks compile. Update LDP generation to accept databricks as an alias for Spark-family casts.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers.\nGOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109.\nDEPENDENCIES: none inherited from parent.\nVERIFICATION: Add compile/emitter tests and run uv/pytest, go test, and lefthook gates.","events_attachment":"tablespec-171e409c/events.jsonl","execution-eligible":false,"id":"tablespec-171e409c","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-ed74497c","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Thread dialect=databricks through compile and LDP emitter paths","updated_at":"2026-07-23T00:26:01.290709015Z"} {"acceptance":"US-041 file exists with stable AC IDs; linked from FEAT-031.","created_at":"2026-07-22T21:41:07.602898557Z","description":"Author US-041 covering JDBC reader and discovery under US-039 goal.","id":"tablespec-1af0828a","issue_type":"task","labels":["helix","phase:frame","area:data","FEAT-031"],"notes":"CLOSED 2026-07-22 queue surgery: US-041 would duplicate US-039 JDBC discovery+onboarding (AC1-6 covered). FEAT-031 no longer requires separate US-041.","parent":"tablespec-263a0248","priority":1,"schema_version":1,"status":"closed","title":"Author US-041: JDBC reader + discovery slices","updated_at":"2026-07-22T21:47:10.78311423Z"} {"acceptance":"US-040 file exists with stable US-040-ACn IDs; each AC cites an existing test path or is marked covered by named test; FEAT-031 user-stories section links US-040; no new product code required unless a citation gap forces a tiny @covers add.","created_at":"2026-07-22T21:41:07.514181186Z","description":"Frame-only backfill. SRC seam and multi-kind source model are SHIPPED (models/umf.py + ingestion/). Author US-040 with US-040-ACn Given/When/Then mapped to existing unit tests (test_source_spec, test_ingestion_package). Do NOT re-implement the seam.","events_attachment":"tablespec-20513f4f/events.jsonl","id":"tablespec-20513f4f","issue_type":"task","labels":["helix","phase:frame","area:data","FEAT-031"],"notes":"Queue surgery 2026-07-22: re-scoped from build to story floor.","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Author US-040: source model + ingestion seam AC backfill (story floor only)","updated_at":"2026-07-22T22:07:10.349061386Z"} {"acceptance":"B1 app FR-23 beads complete or actively blocked only on true deps; JSON residual closed or waived with evidence; story-floor beads closed; tests/docs green; no reopened closed-as-shipped beads without new failing evidence.","created_at":"2026-07-22T21:40:40.237053896Z","description":"Close code/ops gaps against governing HELIX specs after AR-2026-07-22. Specs describe desired future state. Queue surgery 2026-07-22 pruned false residuals (DUMP/PARQ/US-039/US-041/US-038/Trace Links/CORP example). Remaining primary build: B1 app FR-23 path + JSON backbone residual + story floor US-040/042/043/050 + US-045 residual evidence + US-046 @covers.","events":[{"actor":"","body":"closed_because: all_children_terminal\ntotal_children: 21","created_at":"2026-07-22T22:07:16.402671078Z","kind":"epic_auto_close","source":"Store.Close.walkUpClosureCandidate","summary":"auto-closed: all children reached terminal state"}],"id":"tablespec-263a0248","issue_type":"epic","labels":["helix","phase:align","area:specs"],"notes":"Queue surgery 2026-07-22: pruned 7 children as shipped/duplicate/cosmetic.","priority":1,"schema_version":1,"status":"closed","title":"HELIX desired-state alignment — implementation gaps","updated_at":"2026-07-22T22:07:16.406583784Z"} @@ -40,7 +40,7 @@ {"acceptance":"1. A test command such as uv run pytest tests/e2e/test_bootstrap_from_tables.py tests/unit -k bootstrap passes with coverage for the new public facade.\n2. The public API can bootstrap an existing Spark table with one call, using schema reflection for UMF and profile-derived GX expectations when profile=True.\n3. The compiled output includes the UMF snapshot and validation suite produced from the supplied suites.\n4. Public docs/examples show only the new facade for Databricks bootstrap and explain that the profiler enriches validation rather than creating UMF.","closing_commit_sha":"7f1331496f8704eff6a3f1373c69eb4abad58151","created_at":"2026-06-08T00:17:32.10566223Z","description":"Create a first-class public bootstrap API so users and agents do not compose lower-level internals manually. Current implementation has the ingredients but exposes them as separate pieces: src/tablespec/e2e/paths.py umfs_from_tables reflects Spark schema into UMF and optionally builds profile-derived GX suites; src/tablespec/e2e/compile.py compile_umfs persists compiled artifacts. This causes agents to hand-roll SparkToUmfMapper, NativeSparkProfiler, ProfileToGxMapper, and compile_umfs. Add a public, documented one-shot API that points at existing Databricks/Spark tables and returns/persists the full bootstrap result. The native profiler must remain data-profile-only; schema reflection creates UMF; ProfileToGxMapper creates validation expectations; compile persists the validation suite and artifacts.\\n\\nIn-scope files:\\n- src/tablespec/bootstrap.py or equivalent public bootstrap module\\n- src/tablespec/__init__.py exports\\n- docs/ or docs/helix user-facing Databricks bootstrap guidance\\n- tests covering the new facade\\n\\nOut-of-scope for this bead:\\n- Removing or renaming internal e2e/profiling APIs\\n- Inline UMF format removal\\n- Large refactors of sample_data internals","events_attachment":"tablespec-385c98f8/events.jsonl","id":"tablespec-385c98f8","issue_type":"task","labels":["area:bootstrap","area:databricks","kind:api","ac-quality:needs-refinement"],"priority":0,"schema_version":1,"session_id":"eb-254aadb1","spec-id":"FEAT-026","status":"closed","title":"Add one-shot Databricks bootstrap facade","updated_at":"2026-06-08T00:45:22.677762965Z"} {"acceptance":"1. A user-facing happy-path document exists and covers all seven required story beats in order.\n2. The guide clearly distinguishes currently supported commands/API snippets from pending structural improvements tracked by DDx beads.\n3. The guide includes Databricks-safe testing/runtime notes and production install/run boundaries.\n4. Docs index or navigation links make the guide discoverable.\n5. A validation command such as a docs link check, markdown check, or targeted pytest/import check passes and is recorded.","closing_commit_sha":"05973ba7c4fea12d028370a6e3552170dffcdfae","created_at":"2026-06-08T00:43:36.063379313Z","description":"Create a user-facing happy-path guide for tablespec that connects the major product workflows into one coherent story. The guide should show how a user starts from existing tables, generates UMF, generates sample data, validates real and sample data, generates table specification and validation Excel workbooks, defines a derived table, generates Spark/LDP/dbt pipelines, and runs those pipelines. This should be the canonical narrative that agents and users follow instead of discovering low-level APIs piecemeal.\n\nRequired story beats:\n1. Generate UMF from one or more existing Spark/Databricks tables.\n2. Generate sample data from the resulting UMF/spec artifacts.\n3. Validate both real source data and generated sample data.\n4. Generate table specification and validation XLSX files for review/editing.\n5. Define a derived table from source UMFs.\n6. Generate Spark, LDP, and dbt pipeline artifacts from the UMF set.\n7. Run the generated pipelines and distinguish development bootstrap from production install/run.\n\nThe guide must make current gaps explicit rather than hiding them: if a one-shot facade, inline YAML cleanup, Databricks dialect canonicalization, or production JSON/wheel packaging is still pending, point to the relevant DDx beads or state the current supported composition.\n\nIn-scope files:\n- docs/ user-facing happy-path guide and index links\n- docs/helix references only where needed for traceability\n- examples/scripts if a small runnable happy-path script is appropriate\n- tests or docs checks that prove commands/imports in the guide stay valid\n\nOut-of-scope for this bead:\n- Implementing missing facade/packaging/dialect/inline-format work\n- Rewriting all existing docs\n- Adding new runtime capabilities not already available or separately tracked","events_attachment":"tablespec-390cbf1f/events.jsonl","id":"tablespec-390cbf1f","issue_type":"task","labels":["area:docs","area:databricks","area:pipeline","kind:workflow","ac-quality:needs-refinement"],"priority":0,"schema_version":1,"session_id":"eb-feb61d7f","status":"closed","title":"Document end-to-end tablespec happy path","updated_at":"2026-06-08T06:22:34.522569235Z"} {"acceptance":"validation-sync on a valid split spec round-trips loadably; meta_* columns keep UMF type names; a regression test loads the spec after sync; nonzero exit on any write that fails validation.","created_at":"2026-06-12T02:16:38.556346153Z","description":"Site rewrite verification 2026-06-12: sync_baseline.METADATA_COLUMN_DEFINITIONS uses PySpark type names (StringType, TimestampType) that violate the UMF data_type pattern; non-dry-run validation-sync rewrites valid meta_* columns into an unloadable state and still exits 0 reporting 'Already in sync'. Silent spec corruption — the failure class the product exists to prevent. Site docs demonstrate only --dry-run until fixed.","id":"tablespec-3e72dc77","issue_type":"bug","labels":["kind:bug","area:validation","severity:high"],"owner":"erik","priority":1,"schema_version":1,"status":"closed","title":"validation-sync writes PySpark type names into UMF, corrupting split specs (exit 0)","updated_at":"2026-06-12T16:38:07.767057213Z"} -{"acceptance":"1. TestDatabricksDialectContractIsDocumented: add or update a docs/metadata regression test that fails if the accepted dialect list regresses back to spark/duckdb-only wording and omits public dialect=\"databricks\".\n2. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n3. TestGoGate: `go test ./...`\n4. TestLefthookGate: `lefthook run pre-commit`","created_at":"2026-06-08T18:22:28.902935417Z","description":"PROBLEM: The public dialect contract can still be read as spark/duckdb-only, so reviewers and validators may incorrectly reject dialect=\"databricks\" even though the implementation accepts it.\nROOT CAUSE: docs/helix/03-test/conformance-acceptance.md:49, docs/helix/03-test/conformance-acceptance.md:85, and docs/helix/03-test/conformance-acceptance.md:109 are governing acceptance artifacts whose dialect wording does not clearly preserve databricks as an accepted public dialect.\nPROPOSED FIX: Update the conformance/documentation contract and its regression coverage so accepted dialect wording includes databricks alongside spark and duckdb, and fails if it regresses to spark/duckdb-only language.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events":[{"actor":"ddx","body":"{\"resolved_provider\":\"sindri\",\"resolved_model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"fallback_chain\":[]}","created_at":"2026-06-08T20:29:19.486042934Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=sindri model=dflash reason=policy=cheap; score=35.0"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T202242-40596bf9\",\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"input_tokens\":34564,\"output_tokens\":585,\"total_tokens\":35149,\"cost_usd\":0,\"duration_ms\":394944,\"exit_code\":1}","created_at":"2026-06-08T20:29:19.502178422Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=35149 model=dflash"},{"actor":"ddx","body":"{\"actual_harness\":\"fiz\",\"actual_model\":\"dflash\",\"actual_power\":0,\"actual_provider\":\"sindri\",\"attempt_id\":\"20260608T202242-40596bf9\",\"bead_id\":\"tablespec-3ee3b466\",\"estimated_difficulty\":\"easy\",\"rejected_route_pins\":null,\"requested_power_class\":\"cheap\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"readiness\"}","created_at":"2026-06-08T20:29:20.889717265Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=readiness difficulty=easy powerClass=cheap model=dflash harness=fiz"},{"actor":"erik","body":"{\"base_rev\":\"96de4c5e2742d4966eef8d4c03c1efea7707dc75\",\"classification\":\"routing\",\"detail\":\"agent: provider error: openai: POST \\\"http://sindri:8080/v1/chat/completions\\\": 400 Bad Request {\\\"message\\\":\\\"prompt + max_tokens exceeds context window\\\",\\\"type\\\":\\\"invalid_request_error\\\"}\",\"rationale\":\"Attempt failed before implementation because the selected cheap route provider/model dflash could not fit the prompt plus max_tokens in its context window; base_rev and result_rev are unchanged, so this is a model capability/routing mismatch rather than a bead defect.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"96de4c5e2742d4966eef8d4c03c1efea7707dc75\",\"session_id\":\"eb-7f7183d2\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T20:29:49.896488397Z","kind":"bead-quality.triage","source":"ddx work","summary":"routing: release_claim_retry"},{"actor":"erik","body":"agent: provider error: openai: POST \"http://sindri:8080/v1/chat/completions\": 400 Bad Request {\"message\":\"prompt + max_tokens exceeds context window\",\"type\":\"invalid_request_error\"}\npowerClass=cheap\ndecision_audit={\"failure_class\":\"routing\",\"retry_action\":\"retry\",\"escalation_count\":0,\"requested_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"profile\":\"cheap\",\"routing_intent_source\":\"readiness\",\"estimated_difficulty\":\"easy\",\"inferred_power_class\":\"cheap\",\"requested_power_class\":\"cheap\"},\"actual_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"readiness\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=96de4c5e2742d4966eef8d4c03c1efea7707dc75\nbase_rev=96de4c5e2742d4966eef8d4c03c1efea7707dc75\noutcome_reason=routing","created_at":"2026-06-08T20:29:49.904784016Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"ac_map\":[{\"parent_ac\":\"1. TestDatabricksDialectContractIsDocumented: add or update a docs/metadata regression test that fails if the accepted dialect list regresses back to spark/duckdb-only wording and omits public dialect=\\\"databricks\\\".\",\"coverage\":\"child 1 AC1 TestConformanceAcceptedDialectListIncludesDatabricks; child 1 AC2 TestConformanceAcceptedDialectListRejectsSparkDuckdbOnly; child 2 AC1 TestDatabricksOptInTierPreservesPublicDialect; child 2 AC2 TestDatabricksLocalCoverageDoesNotDemoteDialect\"},{\"parent_ac\":\"2. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\",\"coverage\":\"child 1 AC3 TestPytestGate; child 2 AC3 TestPytestGate\"},{\"parent_ac\":\"3. TestGoGate: `go test ./...`\",\"coverage\":\"child 1 AC4 TestGoGate; child 2 AC4 TestGoGate\"},{\"parent_ac\":\"4. TestLefthookGate: `lefthook run pre-commit`\",\"coverage\":\"child 1 AC5 TestLefthookGate; child 2 AC5 TestLefthookGate\"}],\"child_ids\":[\"tablespec-7d18b645\",\"tablespec-37db161f\"],\"rationale\":\"Split by independently reviewable contract surfaces: one child pins the accepted public dialect list and regression guard, while the other pins the Databricks opt-in/local-coverage boundary so it cannot be misread as removing public dialect=\\\"databricks\\\". Both children preserve the parent non-scope, governing artifacts, dependency IDs, and verification gates.\"}","created_at":"2026-06-08T20:34:59.152349424Z","kind":"triage-decomposed","source":"ddx work","summary":"decomposed into tablespec-7d18b645, tablespec-37db161f"}],"execution-eligible":false,"id":"tablespec-3ee3b466","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"parent":"tablespec-943b21a5","priority":0,"schema_version":1,"status":"open","title":"Document databricks as an accepted public dialect","updated_at":"2026-06-08T20:34:59.314003388Z"} +{"acceptance":"1. Conformance docs list spark/duckdb/databricks as accepted public dialects (test_dialect_contract.py).\n2. Pytest: uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py\n3. Pre-commit CI green. (No Go gate — pure Python repo.)","created_at":"2026-06-08T18:22:28.902935417Z","description":"PROBLEM: The public dialect contract can still be read as spark/duckdb-only, so reviewers and validators may incorrectly reject dialect=\"databricks\" even though the implementation accepts it.\nROOT CAUSE: docs/helix/03-test/conformance-acceptance.md:49, docs/helix/03-test/conformance-acceptance.md:85, and docs/helix/03-test/conformance-acceptance.md:109 are governing acceptance artifacts whose dialect wording does not clearly preserve databricks as an accepted public dialect.\nPROPOSED FIX: Update the conformance/documentation contract and its regression coverage so accepted dialect wording includes databricks alongside spark and duckdb, and fails if it regresses to spark/duckdb-only language.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events_attachment":"tablespec-3ee3b466/events.jsonl","execution-eligible":false,"id":"tablespec-3ee3b466","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"parent":"tablespec-943b21a5","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Document databricks as an accepted public dialect","updated_at":"2026-07-23T00:25:58.862795964Z"} {"acceptance":"Either Contract artifacts exist under docs/helix/02-design/ and PRD/US reference them by ID, or a documented waiver exists in docs/helix/01-frame/principles.md or concerns.md naming the no_surface_leak checks as waived and why.","created_at":"2026-06-11T00:23:21.359873657Z","description":"Spec audit 2026-06-10: zero Contract artifacts exist in docs/helix, yet the PRD and user-story meta.yml blocking checks (no_surface_leak) require exact CLI/API/SQL surface to live in Contract artifacts, not inline. PRD FRs name exact CLI commands/signatures (prd.md FR-8.x, FR-16.x); US-001/010/025/026 ACs define exact API/CLI/SQL/config surface inline. helix v0.6.1 SKILL.md now defines the Contract artifact lane (02-design/contract). Either (a) extract the normative surface into Contract artifacts and reference Contract IDs from PRD/US, or (b) record a project policy waiver for no_surface_leak.","id":"tablespec-4323cd4c","issue_type":"task","labels":["helix","spec","decision"],"priority":1,"resolution":"DECIDED 2026-06-10 (operator): ratchet. Existing backfilled specs waived; new/changed surfaces require a Contract artifact under docs/helix/02-design/, CLI contract first when the CLI next changes. Recorded in principles.md §Tension Resolution.","schema_version":1,"status":"closed","title":"DECISION: adopt Contract artifacts or waive no_surface_leak checks","updated_at":"2026-06-11T00:56:02.000268496Z"} {"acceptance":"Provision exits 0 twice on empty then existing environment; documented in deployment-checklist app_deploy.","closing_commit_sha":"6857ad0da3e8839e3fb40c6fe806ee7f4060e562","created_at":"2026-07-22T21:41:07.040621169Z","description":"Add deploy-time provision step that creates/verifies schema, volume, and governance tables. Re-run is a no-op.","events_attachment":"tablespec-48f4fce6/events.jsonl","id":"tablespec-48f4fce6","issue_type":"task","labels":["helix","phase:build","area:app","FEAT-034"],"notes":"[2026-07-22T22:02:14Z] closure rejected: closure gate: insufficient evidence: no execution evidence (empty events and no closing_commit_sha)","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"App: idempotent metadata home provision step (FR-23.3 / US-048)","updated_at":"2026-07-22T22:02:59.656970885Z"} {"acceptance":"pytest tests -k jdbc_umf_mapper passes incl. mapper-generated UMF passing tablespec validate; pytest tests/integration -k jdbc_reader passes vs SQL Server container / SKIPs without Docker; grep proves no pyodbc/jaydebeapi imports in src/.","closing_commit_sha":"08e7de533805ae50719d68047c6df1ceaa46d6ee","created_at":"2026-06-11T02:34:36.542644702Z","dependencies":[{"issue_id":"tablespec-4b65c810","depends_on_id":"tablespec-4bea5c6c","type":"blocks","created_at":"2026-06-11T02:34:36Z"}],"description":"FEAT-031 JDBC-01..05, DISC-01..03. JdbcReader: spark.read.format('jdbc') with options from the source spec; secret-ref resolution at read time (Databricks secret scope / env var); identifier sanitization (lowercase, non-alnum-\u003eunderscore, collapse repeats) with source identifier preserved for the read boundary. JdbcToUmfMapper: enumerate tables + read INFORMATION_SCHEMA (columns, nullability, PK, FK) through the SAME Spark JDBC reader (option('query',...)); column types from the reflected DataFrame schema reused via SparkToUmfMapper. NO direct DB drivers (no pyodbc/JayDeBeApi) anywhere in src/tablespec. Docker-gated SQL Server integration tests (SKIP when Docker absent).","id":"tablespec-4b65c810","issue_type":"task","labels":["helix","area:ingestion","feat-031","phase:2"],"owner":"erik","parent":"tablespec-ef91646f","priority":1,"schema_version":1,"status":"closed","title":"JdbcReader + JdbcToUmfMapper discovery via Spark JDBC (Phase 3+5)","updated_at":"2026-06-11T13:30:53.934807476Z"} @@ -61,7 +61,7 @@ {"acceptance":"Adapter in src/tablespec/validation with unit tests; test_northwind_e2e.py uses it instead of its local _build_report.","created_at":"2026-06-11T13:55:45.728505095Z","description":"US-039 AC6 follow-up (2026-06-11): the e2e test bridges staged ExpectationResults into QualityCheckResults locally to produce a ValidationReport. Promote that bridge into validation/ as a small shipped adapter so consumers get reports from staged execution without a full compile.","id":"tablespec-72c03317","issue_type":"task","labels":["area:validation","feat-031","kind:feature"],"owner":"erik","priority":3,"schema_version":1,"status":"closed","title":"Ship StagedExecutionResult -\u003e ValidationReport adapter","updated_at":"2026-06-12T16:45:37.438595181Z"} {"acceptance":"Each item either promoted to its own refined bead/FEAT requirement or explicitly declined with a recorded reason.","created_at":"2026-06-12T16:50:00.133977772Z","description":"Captured during the 2026-06-12 bronze-input-universe scoping: Excel-as-data-source (vs authoring), a first-class REST API source kind (acquisition stays plumbing for now), Kafka/CDC streaming contracts, and Avro/ORC as riders on the parquet typed-raw bead (tablespec-61da147e — consider folding there). Revisit after the current demo arc ships.","id":"tablespec-79868e6b","issue_type":"task","labels":["parking-lot","area:ingestion"],"owner":"erik","priority":4,"resolution":"DECIDED 2026-06-12: Avro/ORC are declined as a separate bead and folded into the typed-raw file-format rider discussion for tablespec-61da147e because they share the same native-typed raw/cast/suite plumbing as Parquet. Excel-as-data-source is declined for now because FEAT-009 owns Excel as an authoring/review surface, not a bronze acquisition kind. REST API source kind is declined for now because pagination/auth/retry/rate-limit/response-shape semantics need a separate acquisition ADR/epic, not a FEAT-031 refinement. Kafka/CDC streaming contracts are declined for now because FEAT-031 explicitly excludes real-time CDC ingestion and streaming requires a separate architecture decision.","schema_version":1,"status":"closed","title":"Parking lot: remaining bronze input types (Excel-as-data, REST API kind, Kafka/CDC, Avro/ORC rider)","updated_at":"2026-06-12T17:50:52.481099991Z"} {"acceptance":"1. UMFLoader.load() no longer auto-loads arbitrary single-file YAML UMF documents through the normal path; split directories and JSON continue to load.\n2. If inline YAML compatibility remains, it is reachable only through an explicit migration API/CLI path whose name includes migration or legacy.\n3. CLI help/examples no longer present table.umf.yaml as the canonical authoring input for validate/generate/emit/export/explore.\n4. A test command such as uv run pytest tests/unit/test_umf_loader.py tests/unit/test_cli.py -k \"format or inline or convert\" passes and includes a regression that single-file YAML is rejected or migration-only.\n5. Specs/docs consistently state: split YAML directory for editing, JSON for artifact/interchange, inline YAML is not a supported canonical format.","closing_commit_sha":"8477c81738230fc73dfcbe2c82f07346fbc74535","created_at":"2026-06-08T00:18:06.152420213Z","description":"Remove inline whole-UMF YAML from the normal public authoring/loading path. Product/spec language treats split YAML directories as the editable format and JSON as the artifact/interchange format, but src/tablespec/umf_loader.py still exposes UMFFormat.INLINE and detect_format() auto-detects any .yaml/.yml/.umf file as a whole-UMF document. CLI examples and fixtures using *.umf.yaml make agents default to an inline YAML format that should not be canonical. Preserve any needed compatibility as an explicit migration path only, not autodetected normal loading.\n\nCurrent evidence:\n- src/tablespec/umf_loader.py defines UMFFormat.INLINE and _load_inline_yaml().\n- detect_format() returns INLINE for .yaml/.yml/.umf files.\n- CLI examples mention table.umf.yaml for validate/generate/emit/export/explore.\n- specs name split and JSON as the supported formats for normal workflows.\n\nIn-scope files:\n- src/tablespec/umf_loader.py\n- src/tablespec/cli.py user-facing examples/errors and any explicit migration command if kept\n- docs/helix format requirements and user stories that still imply inline YAML\n- tests for loader/CLI format detection\n\nOut-of-scope for this bead:\n- Rewriting every conformance fixture unless required by tests\n- Changing compiled artifact snapshot format without a separate decision\n- Bootstrap facade work","events_attachment":"tablespec-7bce0707/events.jsonl","id":"tablespec-7bce0707","issue_type":"task","labels":["area:umf-loader","area:formats","kind:api"],"priority":0,"schema_version":1,"session_id":"eb-8f77922a","spec-id":"FEAT-010","status":"closed","title":"Quarantine inline YAML UMF as migration-only","updated_at":"2026-06-08T01:27:55.860961576Z"} -{"acceptance":"1. TestConformanceAcceptedDialectListIncludesDatabricks: add or update tests/docs/test_dialect_contract.py so it reads docs/helix/03-test/conformance-acceptance.md and fails unless the accepted public dialect wording names spark, duckdb, and databricks and includes public dialect=\"databricks\".\n2. TestConformanceAcceptedDialectListRejectsSparkDuckdbOnly: add or update the same docs regression so it fails on spark/duckdb-only accepted dialect language that omits databricks.\n3. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n4. TestGoGate: `go test ./...`\n5. TestLefthookGate: `lefthook run pre-commit`","created_at":"2026-06-08T20:34:59.152352174Z","description":"PROBLEM: The conformance acceptance artifact can still be read as spark/duckdb-only at the public dialect contract boundary, so reviewers and validators may incorrectly reject dialect=\"databricks\" even though the implementation accepts it.\nROOT CAUSE: docs/helix/03-test/conformance-acceptance.md:49 describes the DbtDatabricks compile tier without explicitly tying it to the accepted public dialect list, and docs/helix/03-test/conformance-acceptance.md:93 documents the Databricks-facing compile UX separately from the spark/duckdb dialect contract.\nPROPOSED FIX: Update docs/helix/03-test/conformance-acceptance.md so the accepted public dialect wording explicitly includes databricks alongside spark and duckdb, while preserving that internal Spark-family renderers may normalize the spelling when SQL is identical. Add a focused docs regression that fails if the accepted dialect wording regresses to spark/duckdb-only or omits dialect=\"databricks\".\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; child of tablespec-943b21a5; no additional dependencies.","events":[{"actor":"ddx","body":"{\"resolved_provider\":\"codex\",\"resolved_model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"fallback_chain\":[]}","created_at":"2026-06-09T01:18:51.656650693Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=codex model=gpt-5.4-mini reason=explicit_pin_discovery_unavailable"},{"actor":"ddx","body":"{\"attempt_id\":\"20260609T004515-a93571b6\",\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"input_tokens\":1055131,\"output_tokens\":14220,\"total_tokens\":1069351,\"cost_usd\":0,\"duration_ms\":240866,\"exit_code\":0}","created_at":"2026-06-09T01:18:51.683482203Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=1069351 model=gpt-5.4-mini"},{"actor":"ddx","body":"{\"actual_harness\":\"codex\",\"actual_model\":\"gpt-5.4-mini\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"20260609T004515-a93571b6\",\"bead_id\":\"tablespec-7d18b645\",\"estimated_difficulty\":\"easy\",\"rejected_route_pins\":null,\"requested_power_class\":\"cheap\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"readiness\"}","created_at":"2026-06-09T01:19:02.280561579Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=readiness difficulty=easy powerClass=cheap model=gpt-5.4-mini harness=codex"},{"actor":"erik","body":"status=blocked\nreason=external blocker - `go test ./...` cannot run in this worktree because there is no Go module or Go source tree here; the command exits `pattern ./...: directory prefix . does not contain main module or its selected dependencies`.\nsuggested_action=recheck the external blocker and move status to open when cleared","created_at":"2026-06-09T01:19:02.353228786Z","kind":"no_changes_blocked","source":"ddx work","summary":"no_changes_blocked"},{"actor":"erik","body":"no_changes\npowerClass=cheap\nrationale: status: blocked\nreason: external blocker - `go test ./...` cannot run in this worktree because there is no Go module or Go source tree here; the command exits `pattern ./...: directory prefix . does not contain main module or its selected dependencies`.\ndecision_audit={\"failure_class\":\"no_changes\",\"retry_action\":\"retry\",\"escalation_count\":1,\"requested_route\":{\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"profile\":\"cheap\",\"routing_intent_source\":\"readiness\",\"estimated_difficulty\":\"easy\",\"inferred_power_class\":\"cheap\",\"requested_power_class\":\"cheap\"},\"actual_route\":{\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"readiness\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=dc2ff514a32349e5ab5577bb548fe86fc43bef65\nbase_rev=dc2ff514a32349e5ab5577bb548fe86fc43bef65\noutcome_reason=no_changes","created_at":"2026-06-09T01:19:02.372544555Z","kind":"execute-bead","source":"ddx work","summary":"no_changes"}],"id":"tablespec-7d18b645","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"lifecycle-external-blocker-reason":"external blocker - `go test ./...` cannot run in this worktree because there is no Go module or Go source tree here; the command exits `pattern ./...: directory prefix . does not contain main module or its selected dependencies`.","parent":"tablespec-3ee3b466","priority":0,"schema_version":1,"status":"blocked","title":"Clarify conformance artifact accepted dialect list includes databricks","updated_at":"2026-06-09T01:19:02.378120548Z","work-last-detail":"external blocker - `go test ./...` cannot run in this worktree because there is no Go module or Go source tree here; the command exits `pattern ./...: directory prefix . does not contain main module or its selected dependencies`.","work-last-status":"no_changes_blocked","work-no-changes-count":1,"work-suggested-action":"recheck the external blocker and move status to open when cleared"} +{"acceptance":"1. TestConformanceAcceptedDialectListIncludesDatabricks: tests/docs/test_dialect_contract.py asserts accepted public dialects name spark, duckdb, and databricks.\n2. TestConformanceAcceptedDialectListRejectsSparkDuckdbOnly: same module fails on spark/duckdb-only wording.\n3. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n4. TestPreCommitGate: `pre-commit run --files tests/docs/test_dialect_contract.py docs/helix/03-test/conformance-acceptance.md` (or full pre-commit CI).\nNote: `go test ./...` is not a gate for this pure-Python repository.","created_at":"2026-06-08T20:34:59.152352174Z","description":"PROBLEM: The conformance acceptance artifact can still be read as spark/duckdb-only at the public dialect contract boundary, so reviewers and validators may incorrectly reject dialect=\"databricks\" even though the implementation accepts it.\nROOT CAUSE: docs/helix/03-test/conformance-acceptance.md:49 describes the DbtDatabricks compile tier without explicitly tying it to the accepted public dialect list, and docs/helix/03-test/conformance-acceptance.md:93 documents the Databricks-facing compile UX separately from the spark/duckdb dialect contract.\nPROPOSED FIX: Update docs/helix/03-test/conformance-acceptance.md so the accepted public dialect wording explicitly includes databricks alongside spark and duckdb, while preserving that internal Spark-family renderers may normalize the spelling when SQL is identical. Add a focused docs regression that fails if the accepted dialect wording regresses to spark/duckdb-only or omits dialect=\"databricks\".\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; child of tablespec-943b21a5; no additional dependencies.","events_attachment":"tablespec-7d18b645/events.jsonl","id":"tablespec-7d18b645","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"owner":"erik","parent":"tablespec-3ee3b466","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Clarify conformance artifact accepted dialect list includes databricks","updated_at":"2026-07-23T00:25:56.112800693Z","work-last-detail":"external blocker - `go test ./...` cannot run in this worktree because there is no Go module or Go source tree here; the command exits `pattern ./...: directory prefix . does not contain main module or its selected dependencies`.","work-last-status":"no_changes_blocked","work-no-changes-count":1,"work-suggested-action":"recheck the external blocker and move status to open when cleared"} {"acceptance":"Tests assert multi-char terminators, null escapes, footer handling, skip_rows.","created_at":"2026-07-22T21:41:07.985967956Z","dependencies":[{"issue_id":"tablespec-7ec86390","depends_on_id":"tablespec-e322b612","type":"blocks","created_at":"2026-07-22T21:41:07Z"}],"description":"Every declared dump dialect option consumed by compiled readers; fixture coverage.","id":"tablespec-7ec86390","issue_type":"task","labels":["helix","phase:build","area:data","FEAT-031"],"notes":"CLOSED 2026-07-22 queue surgery: DUMP-01..04 shipped — model options + dump reader + test_ingestion_package dump tests. FEAT-031/PRD FR-21.2 marked Shipped.","parent":"tablespec-263a0248","priority":1,"schema_version":1,"status":"closed","title":"Implement dump-dialect end-to-end (DUMP-01..04)","updated_at":"2026-07-22T21:47:09.543809991Z"} {"acceptance":"Each re-authored FEAT passes structural conformance against template.md required sections; registry row updated; no phantom claims (every code citation verified).","created_at":"2026-06-11T00:23:44.272289169Z","description":"Spec audit 2026-06-10: FEAT-001..023 are registry-style cards (Description/Components/User Stories/Source) missing all six required template sections (problem_statement, requirements, edge_cases_and_error_handling, success_metrics, constraints_and_assumptions, out_of_scope). FEAT-024..029 are the conformant exemplars. Re-author incrementally (worst-first; suggest FEAT-007, FEAT-008, FEAT-004 first since they govern the largest subsystems). Template: .ddx/plugins/helix/workflows/activities/01-frame/artifacts/feature-specification/.","id":"tablespec-82d79e00","issue_type":"task","labels":["helix","spec","backfill"],"owner":"erik","priority":2,"schema_version":1,"status":"closed","title":"Re-author FEAT-001..023 to full feature-specification template","updated_at":"2026-06-11T02:46:25.753131479Z"} {"acceptance":"Automated search of tracked app source returns no environment-identifying literals (fixtures may use synthetic names).","closing_commit_sha":"6857ad0da3e8839e3fb40c6fe806ee7f4060e562","created_at":"2026-07-22T21:41:06.929450331Z","dependencies":[{"issue_id":"tablespec-859aa1ea","depends_on_id":"tablespec-2a68a0ad","type":"blocks","created_at":"2026-07-22T21:41:06Z"}],"description":"Tracked application source must not embed catalog, schema, volume, warehouse id, or workspace URL. Add a grep/test gate.","events_attachment":"tablespec-859aa1ea/events.jsonl","id":"tablespec-859aa1ea","issue_type":"task","labels":["helix","phase:build","area:app","FEAT-034"],"notes":"[2026-07-22T22:02:15Z] closure rejected: closure gate: insufficient evidence: no execution evidence (empty events and no closing_commit_sha)","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"App: strip environment-identifying literals (FR-23.1 / CFG-02)","updated_at":"2026-07-22T22:03:02.07513218Z"} @@ -69,7 +69,7 @@ {"acceptance":"All US-039 ACs (AC1-AC6) pass on the Docker lane; databricks_e2e lane green when credentials configured; evidence recorded (commands + exit status) in the bead.","closing_commit_sha":"224a8af9789d52195ccec8d91c7009fd82ba027b","created_at":"2026-06-11T02:34:36.619401849Z","dependencies":[{"issue_id":"tablespec-8980c812","depends_on_id":"tablespec-4b65c810","type":"blocks","created_at":"2026-06-11T02:34:36Z"}],"description":"Drive US-039 ACs: Northwind in SQL Server -\u003e discover one UMF per table (FKs incl. orders.customer_id-\u003ecustomers.customer_id; 'Order Details'-\u003eorder_details sanitization) -\u003e tablespec validate all pass -\u003e export-excel workbook round-trips -\u003e FK-aware sample data -\u003e staged validation report per table with real results and zero silent NULL-out of typed columns. Local lane: Docker SQL Server + Northwind, SKIP without Docker. Databricks lane: opt-in databricks_e2e tier. Consumer integration (entropy-exchange 03_etl.py replacement) follows in that repo.","id":"tablespec-8980c812","issue_type":"task","labels":["helix","area:ingestion","feat-031","phase:3","acceptance-goal"],"owner":"erik","parent":"tablespec-ef91646f","priority":1,"schema_version":1,"status":"closed","title":"US-039 Northwind end-to-end acceptance (Docker lane + databricks_e2e)","updated_at":"2026-06-11T13:55:45.336976785Z"} {"acceptance":"Checklist has the required sections with measurable decision points and is execution-ready for the next release.","created_at":"2026-06-11T00:24:15.631071468Z","description":"Spec audit 2026-06-10: docs/helix/05-deploy/deployment-checklist.md is a descriptive backfill of release.yml; missing release_scope, rollout_plan, rollback_triggers (has steps, no thresholds), go_or_no_go_decision; blocking measurable_decision_points check unmet; not execution-ready (no checkboxes/owners/window).","id":"tablespec-8a432681","issue_type":"task","labels":["helix","spec","backfill"],"owner":"erik","priority":3,"schema_version":1,"status":"closed","title":"Restructure deployment-checklist.md to template (rollout, rollback triggers, go/no-go)","updated_at":"2026-06-12T16:49:44.346035199Z"} {"acceptance":"1. TestCompileUmfsAcceptsDatabricksDialect: add a compile-path test proving compile_umfs(..., dialect=\"databricks\") completes without ValueError and persists ingest, dbt_ingest, optional dbt_gold, LDP, and manifest artifacts under the pinned layout.\n2. TestCompileUmfsPreservesPublicDialectInManifest: add a regression test proving the generated metadata records the public databricks dialect while any Spark-family internal normalization remains invisible to downstream artifact consumers.\n3. TestPytestGate: `uv run pytest tests/unit/test_bootstrap.py tests/e2e/test_bootstrap_from_specs.py`\n4. TestGoGate: `go test ./...`\n5. TestLefthookGate: `lefthook run pre-commit`","closing_commit_sha":"73a4d3cab2ccb57de6daf5527f7d3c495232c6dc","created_at":"2026-06-08T14:50:25.00456272Z","description":"PROBLEM: The compile/bootstrap path can receive dialect=databricks, but the artifact pipeline still mixes public and internal dialect handling, so the emitted ingest/dbt_ingest/LDP/manifest set can reject databricks or record the wrong dialect.\nROOT CAUSE: src/tablespec/e2e/compile.py:129 forwards the caller dialect to generate_dbt_dag_project, src/tablespec/e2e/compile.py:141 hard-codes generate_ldp_project(..., dialect=\"spark\"), src/tablespec/e2e/compile.py:193 calls generate_ingest_sql without a dialect, and src/tablespec/schemas/ingest_generator.py:214 hard-codes build_ingest_select(..., dialect=\"spark\").\nPROPOSED FIX: Thread the public databricks dialect through compile_umfs, normalize Spark-family emitters internally only where SQL is identical, keep dbt target selection as databricks, and preserve the public dialect in generated metadata while still emitting the pinned artifact layout.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events_attachment":"tablespec-924c7384/events.jsonl","id":"tablespec-924c7384","issue_type":"task","labels":["area:databricks","area:dialects","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-171e409c","priority":0,"schema_version":1,"session_id":"eb-e961169d","status":"closed","title":"Thread databricks through compile-path normalization","updated_at":"2026-06-08T15:41:34.831875417Z"} -{"acceptance":"1. TestDatabricksCompileArtifactsStateNormalizationDecision: assert the implementation notes or generated metadata/comments state the decision: public dialect=\"databricks\" is accepted and Spark-family SQL emitters may normalize to spark internally because cast SQL is identical.\n2. TestDatabricksDialectContractIsDocumented: add a docs or metadata regression test that fails if the accepted dialect list regresses back to spark/duckdb-only wording.\n3. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n4. TestGoGate: `go test ./...`\n5. TestLefthookGate: `lefthook run pre-commit`","created_at":"2026-06-08T14:50:25.086649929Z","description":"PROBLEM: The public contract still reads like Spark/duckdb-only support in places, so even after code paths accept databricks, downstream reviewers and validators can still infer the wrong supported dialect set.\nROOT CAUSE: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84 and docs/helix/03-test/conformance-acceptance.md:49, docs/helix/03-test/conformance-acceptance.md:85, and docs/helix/03-test/conformance-acceptance.md:109 are the governing acceptance artifacts, but the implementation notes and emitted metadata/comments do not clearly state that public dialect=\"databricks\" is accepted while Spark-family emitters may normalize internally.\nPROPOSED FIX: Update implementation notes, comments, or generated metadata to spell out the dialect contract, including the Spark-family normalization decision and the reason it is safe because the cast SQL is identical.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events":[{"actor":"erik","body":"{\"ac_map\":[{\"parent_ac\":\"1. TestDatabricksCompileArtifactsStateNormalizationDecision: assert the implementation notes or generated metadata/comments state the decision: public dialect=\\\"databricks\\\" is accepted and Spark-family SQL emitters may normalize to spark internally because cast SQL is identical.\",\"coverage\":\"Child \\\"Document Spark-family normalization for databricks emitters\\\" AC1 TestDatabricksCompileArtifactsStateNormalizationDecision.\"},{\"parent_ac\":\"2. TestDatabricksDialectContractIsDocumented: add a docs or metadata regression test that fails if the accepted dialect list regresses back to spark/duckdb-only wording.\",\"coverage\":\"Child \\\"Document databricks as an accepted public dialect\\\" AC1 TestDatabricksDialectContractIsDocumented.\"},{\"parent_ac\":\"3. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\",\"coverage\":\"Child \\\"Document databricks as an accepted public dialect\\\" AC2 TestPytestGate and child \\\"Document Spark-family normalization for databricks emitters\\\" AC2 TestPytestGate.\"},{\"parent_ac\":\"4. TestGoGate: `go test ./...`\",\"coverage\":\"Child \\\"Document databricks as an accepted public dialect\\\" AC3 TestGoGate and child \\\"Document Spark-family normalization for databricks emitters\\\" AC3 TestGoGate.\"},{\"parent_ac\":\"5. TestLefthookGate: `lefthook run pre-commit`\",\"coverage\":\"Child \\\"Document databricks as an accepted public dialect\\\" AC4 TestLefthookGate and child \\\"Document Spark-family normalization for databricks emitters\\\" AC4 TestLefthookGate.\"}],\"child_ids\":[\"tablespec-3ee3b466\",\"tablespec-c65a49de\"],\"rationale\":\"Split by independently verifiable contract surfaces: one child protects the public accepted dialect list in conformance documentation, while the other protects implementation/generated-artifact wording for Spark-family normalization. Both retain the parent non-scope, governing artifacts, dependency context, pytest command, go test gate, and lefthook gate.\"}","created_at":"2026-06-08T18:22:28.902933376Z","kind":"triage-decomposed","source":"ddx work","summary":"decomposed into tablespec-3ee3b466, tablespec-c65a49de"}],"execution-eligible":false,"id":"tablespec-943b21a5","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-171e409c","priority":0,"schema_version":1,"status":"open","title":"Document the databricks dialect contract and normalization rule","updated_at":"2026-06-08T18:22:29.012524601Z"} +{"acceptance":"1. Normalization decision documented in compile.py + conformance-acceptance.md.\n2. Docs regression + normalize_cast_dialect tests.\n3. Pytest + pre-commit. (No Go gate — pure Python repo.)","created_at":"2026-06-08T14:50:25.086649929Z","description":"PROBLEM: The public contract still reads like Spark/duckdb-only support in places, so even after code paths accept databricks, downstream reviewers and validators can still infer the wrong supported dialect set.\nROOT CAUSE: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84 and docs/helix/03-test/conformance-acceptance.md:49, docs/helix/03-test/conformance-acceptance.md:85, and docs/helix/03-test/conformance-acceptance.md:109 are the governing acceptance artifacts, but the implementation notes and emitted metadata/comments do not clearly state that public dialect=\"databricks\" is accepted while Spark-family emitters may normalize internally.\nPROPOSED FIX: Update implementation notes, comments, or generated metadata to spell out the dialect contract, including the Spark-family normalization decision and the reason it is safe because the cast SQL is identical.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events_attachment":"tablespec-943b21a5/events.jsonl","execution-eligible":false,"id":"tablespec-943b21a5","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-171e409c","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Document the databricks dialect contract and normalization rule","updated_at":"2026-07-23T00:26:00.229083238Z"} {"acceptance":"Each US-046-AC has a named test with @covers US-046-ACn or a documented non-automatable exception.","created_at":"2026-07-22T21:41:08.54317106Z","description":"Guidebook generation tests exist (test_guidebook_generate.py etc.) but lack @covers US-046-ACn. Add citations or document exceptions; do not re-implement guidebook.","events_attachment":"tablespec-9c79765e/events.jsonl","id":"tablespec-9c79765e","issue_type":"task","labels":["helix","phase:test","area:docs","FEAT-033"],"notes":"Queue surgery 2026-07-22: confirmed hygiene-only; kept.","owner":"erik","parent":"tablespec-263a0248","priority":3,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Link US-046 guidebook ACs to tests","updated_at":"2026-07-22T22:07:14.196384917Z"} {"acceptance":"1. .agents/skills/tablespec/SKILL.md exists with valid skill frontmatter name=tablespec and a description that triggers for tablespec code/spec/Databricks/UMF/pipeline work.\n2. The skill body is concise and includes the canonical workflow guidance listed in the description without duplicating full specs.\n3. Any optional agents/openai.yaml metadata, if present, is consistent with SKILL.md.\n4. A validation command such as python - \u003c\u003cPY to parse the YAML frontmatter, or an available skill validation script, passes.\n5. The bead is closed with evidence after the skill file is committed.","closing_commit_sha":"b2515b1d3e2ba98cbfba870b1a7ed3eaf79a47c7","created_at":"2026-06-08T00:42:02.12152395Z","description":"Add a concise project-local agent skill for tablespec so coding agents discover the canonical public workflows before low-level internals. The skill should be a routing/onboarding layer, not a duplicate copy of the specs. It should steer agents away from recurring drift: hand-rolling SparkToUmfMapper/NativeSparkProfiler/ProfileToGxMapper composition, treating inline YAML UMF as canonical, confusing Databricks target/runtime with cast dialect, and treating production as notebook-local source orchestration instead of installed JSON pipeline artifacts plus wheels.\n\nRequired guidance in the skill:\n- Prefer public bootstrap/packaging APIs and documented flows over composing internal e2e/profiling modules directly.\n- Schema reflection creates UMF; native profiling creates profile data; ProfileToGxMapper creates validation expectations.\n- UMF authoring format is split YAML directory; JSON is artifact/interchange; inline YAML is legacy/migration-only.\n- Databricks dialect handling must follow the canonical repo decision once implemented; until then call out the current decision bead.\n- Production pipeline contract: production runs installed JSON pipeline artifacts and installed wheels; development builds those artifacts.\n- Databricks tests run in-process with ipytest/pytest.main, not uv run pytest on the Databricks runtime.\n- Tracker work uses DDx beads.\n\nIn-scope files:\n- .agents/skills/tablespec/SKILL.md\n- optional .agents/skills/tablespec/agents/openai.yaml if metadata tooling is available\n- any lightweight validation test or script needed to ensure skill frontmatter is parseable\n\nOut-of-scope for this bead:\n- Implementing bootstrap facade, inline YAML cleanup, dialect canonicalization, or production packaging work\n- Copying full PRD/spec content into the skill\n- Changing DDx itself","id":"tablespec-9f12f29c","issue_type":"task","labels":["area:agents","area:docs","area:databricks","kind:tooling"],"owner":"erik","priority":0,"schema_version":1,"status":"closed","title":"Add project-local tablespec agent skill","updated_at":"2026-06-08T00:46:30.062270831Z"} {"acceptance":"US-050 ACs green for compile/backbone json path, or residual documented with evidence; backbone no longer fails closed on kind=json without a supported path.","created_at":"2026-07-22T21:41:08.163880947Z","dependencies":[{"issue_id":"tablespec-9f98cf03","depends_on_id":"tablespec-557f8a24","type":"blocks","created_at":"2026-07-22T21:41:08Z"}],"description":"Close residual FR-21.7 gaps beyond model and JsonReader. Primary gap: e2e/backbone.py supports only delimited/parquet for raw load. Implement json path (and any compile residual) per US-050 ACs.","events_attachment":"tablespec-9f98cf03/events.jsonl","id":"tablespec-9f98cf03","issue_type":"task","labels":["helix","phase:build","area:data","FEAT-031"],"notes":"Queue surgery 2026-07-22: confirmed real gap; kept.","owner":"erik","parent":"tablespec-263a0248","priority":2,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Implement JSON source residual compile/backbone path","updated_at":"2026-07-22T22:07:13.331375723Z"} @@ -82,7 +82,7 @@ {"acceptance":"File conforms to the solution-design template (or a deliberate local type is registered for design notes); PRD pointer updated if renamed.","created_at":"2026-06-11T00:24:15.702352112Z","description":"Spec audit 2026-06-10: docs/helix/02-design/ldp-sibling-emitter.md is a self-styled governed design note matching no catalog type; nearest type is solution-design (governs FEAT-028). It informally covers scope/requirements/trade-offs/test traceability but lacks Solution Approaches, Domain Model, NFR table, and Traceability table sections. ddx.id frontmatter was added 2026-06-10; full lift needs authoring. PRD Open Questions already records the note is 'retained as the detailed solution design' (prd.md ~line 346).","id":"tablespec-a73d2b87","issue_type":"task","labels":["helix","spec","backfill"],"owner":"erik","priority":3,"schema_version":1,"status":"closed","title":"Lift ldp-sibling-emitter.md design note to solution-design (SD-028)","updated_at":"2026-06-12T16:59:25.249076447Z"} {"acceptance":"Feature and user-story statuses use a consistent vocabulary; every status is backed by implementation/test evidence or explicitly remains planned/specified; stale Done/Approved/Proposed prose is normalized; helix_align_check --strict remains clean.","closing_commit_sha":"91dc5ac7791e64cf5a614c8bee12e04fff912028","created_at":"2026-06-07T20:59:25.434814133Z","description":"Several feature and user-story statuses are stale or inconsistent with implementation evidence. Examples: FEAT-016/017/019/020/021/022/023 are Proposed while their linked stories and tests indicate implemented slices; FEAT-015 and US-028 are Planned while API docs traceability tests now exist; US-021/023/024/026 remain Approved despite test coverage and implemented feature surfaces.","events_attachment":"tablespec-aad04c07/events.jsonl","id":"tablespec-aad04c07","issue_type":"task","labels":["spec","helix","alignment"],"priority":1,"schema_version":1,"session_id":"eb-e75210e0","status":"closed","title":"Reconcile spec status drift with implementation evidence","updated_at":"2026-06-08T00:31:58.006905216Z"} {"acceptance":"Each US-045 AC is either evidenced (command + exit status or @covers test) or explicitly waived with recorded limitation; US-045 and FEAT-032 DEMO phase status updated to match.","created_at":"2026-07-22T21:41:08.448279865Z","description":"EMBEDDING type core and CORP example (examples/sec10k_corpus.yaml) are shipped. This bead only closes remaining US-045 ACs that lack recorded evidence from notebooks/sec-10k-demo or CI. Do not re-implement the type alphabet.","events_attachment":"tablespec-abd68023/events.jsonl","id":"tablespec-abd68023","issue_type":"task","labels":["helix","phase:test","area:data","FEAT-032"],"notes":"Queue surgery 2026-07-22: re-scoped to residual AC evidence only.","owner":"erik","parent":"tablespec-263a0248","priority":2,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Evidence remaining US-045 SEC 10-K demo ACs (residual only)","updated_at":"2026-07-22T22:07:14.987472207Z"} -{"acceptance":"1. Implement the first bounded slice of the parent bead.\n2. cd cli \u0026\u0026 go test ./... passes.\n3. lefthook run pre-commit passes.","created_at":"2026-06-08T00:25:01.512286299Z","description":"PROBLEM\nParent bead tablespec-dbf90b8d is too broad for one execution pass. This child owns part 1 of 2 of that parent scope.\n\nROOT CAUSE\nUS-001 through US-020 still use legacy unchecked acceptance bullets without stable US-NNN-ACx IDs. The Helix align checker currently reports 52/52 cited ACs, but those legacy bullets are not machine-addressable and are effectively outside the coverage matrix.\n\nPROPOSED FIX\nImplement only this child acceptance slice:\n- Implement the first bounded slice of the parent bead.\n\nNON-SCOPE\nDo not implement parent acceptance criteria assigned to sibling child beads. Preserve every parent non-scope constraint unless this child explicitly narrows it.","events":[{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"ambiguous_scope: The bead is already decomposed into a child slice and has two concrete build-gate ACs, but AC1 is still placeholder prose ('first bounded slice') rather than a machine-addressable scope statement. Targeted metadata/AC edits can make it executable without changing intent, so this is refineable rather than a split or operator-blocker.\",\"fingerprint\":\"0d98334aa1edf1a2103f74d1a7d54fd3e7d6341c98dd61ba34aeea9a44c6a099\",\"policy_mode\":\"warn-only\",\"reason\":\"readiness_best_effort\",\"rule_id\":\"pre_claim_intake.readiness_best_effort\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"0d98334aa1edf1a2103f74d1a7d54fd3e7d6341c98dd61ba34aeea9a44c6a099\"}","created_at":"2026-06-08T01:08:53.289201457Z","kind":"intake.warn","source":"ddx work","summary":"readiness_best_effort"},{"actor":"ddx","body":"{\"resolved_provider\":\"codex\",\"resolved_model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"fallback_chain\":[]}","created_at":"2026-06-08T01:13:45.769963455Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=codex model=gpt-5.4-mini reason=explicit_pin_discovery_unavailable"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T010854-c123202c\",\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"input_tokens\":3302764,\"output_tokens\":17778,\"total_tokens\":3320542,\"cost_usd\":0,\"duration_ms\":289796,\"exit_code\":0}","created_at":"2026-06-08T01:13:45.777875639Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=3320542 model=gpt-5.4-mini"},{"actor":"ddx","body":"{\"resolved_provider\":\"codex\",\"resolved_model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"fallback_chain\":[],\"requested_min_power\":5}","created_at":"2026-06-08T01:54:53.069393664Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=codex model=gpt-5.4-mini reason=explicit_pin_discovery_unavailable"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T011347-f6a350e9\",\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"input_tokens\":2936120,\"output_tokens\":27986,\"total_tokens\":2964106,\"cost_usd\":0,\"duration_ms\":422829,\"exit_code\":0}","created_at":"2026-06-08T01:54:53.100400235Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=2964106 model=gpt-5.4-mini"},{"actor":"ddx","body":"{\"actual_harness\":\"codex\",\"actual_model\":\"gpt-5.4-mini\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"20260608T011347-f6a350e9\",\"bead_id\":\"tablespec-b474ae20\",\"estimated_difficulty\":\"medium\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"readiness\"}","created_at":"2026-06-08T01:55:10.508691203Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=readiness difficulty=medium powerClass=standard model=gpt-5.4-mini harness=codex"},{"actor":"erik","body":"status=blocked\nreason=This worktree does not contain a `cli/` directory or any `go.mod`, so the required `cd cli \u0026\u0026 go test ./...` gate cannot be executed here. `lefthook run pre-commit` also has no lefthook config in this worktree, so the second required gate is not runnable as specified.\nsuggested_action=recheck the external blocker and move status to open when cleared","created_at":"2026-06-08T01:55:10.561936937Z","kind":"no_changes_blocked","source":"ddx work","summary":"no_changes_blocked"},{"actor":"erik","body":"no_changes\npowerClass=standard\nrationale: status: blocked\nreason: This worktree does not contain a `cli/` directory or any `go.mod`, so the required `cd cli \u0026\u0026 go test ./...` gate cannot be executed here. `lefthook run pre-commit` also has no lefthook config in this worktree, so the second required gate is not runnable as specified.\nresult_rev=59bea1ed48dc82bcd603cd6f0cec5f66ebe682cd\nbase_rev=59bea1ed48dc82bcd603cd6f0cec5f66ebe682cd\noutcome_reason=no_changes","created_at":"2026-06-08T01:55:10.609406691Z","kind":"execute-bead","source":"ddx work","summary":"no_changes"}],"id":"tablespec-b474ae20","issue_type":"task","labels":["spec","helix","traceability","decomposed"],"lifecycle-external-blocker-reason":"This worktree does not contain a `cli/` directory or any `go.mod`, so the required `cd cli \u0026\u0026 go test ./...` gate cannot be executed here. `lefthook run pre-commit` also has no lefthook config in this worktree, so the second required gate is not runnable as specified.","parent":"tablespec-dbf90b8d","priority":0,"schema_version":1,"status":"blocked","title":"Normalize legacy user-story acceptance criteria: part 1","updated_at":"2026-06-08T01:55:10.610731238Z","work-last-detail":"This worktree does not contain a `cli/` directory or any `go.mod`, so the required `cd cli \u0026\u0026 go test ./...` gate cannot be executed here. `lefthook run pre-commit` also has no lefthook config in this worktree, so the second required gate is not runnable as specified.","work-last-status":"no_changes_blocked","work-no-changes-count":1,"work-suggested-action":"recheck the external blocker and move status to open when cleared"} +{"acceptance":"1. US-001 through US-020 ACs have stable US-NNN-ACx IDs (already on disk). 2. Pytest/pre-commit gates for this Python repo (no Go gate).","created_at":"2026-06-08T00:25:01.512286299Z","description":"PROBLEM\nParent bead tablespec-dbf90b8d is too broad for one execution pass. This child owns part 1 of 2 of that parent scope.\n\nROOT CAUSE\nUS-001 through US-020 still use legacy unchecked acceptance bullets without stable US-NNN-ACx IDs. The Helix align checker currently reports 52/52 cited ACs, but those legacy bullets are not machine-addressable and are effectively outside the coverage matrix.\n\nPROPOSED FIX\nImplement only this child acceptance slice:\n- Implement the first bounded slice of the parent bead.\n\nNON-SCOPE\nDo not implement parent acceptance criteria assigned to sibling child beads. Preserve every parent non-scope constraint unless this child explicitly narrows it.","events_attachment":"tablespec-b474ae20/events.jsonl","id":"tablespec-b474ae20","issue_type":"task","labels":["spec","helix","traceability","decomposed"],"owner":"erik","parent":"tablespec-dbf90b8d","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Normalize legacy user-story acceptance criteria: part 1","updated_at":"2026-07-23T00:27:46.286570427Z","work-last-detail":"This worktree does not contain a `cli/` directory or any `go.mod`, so the required `cd cli \u0026\u0026 go test ./...` gate cannot be executed here. `lefthook run pre-commit` also has no lefthook config in this worktree, so the second required gate is not runnable as specified.","work-last-status":"no_changes_blocked","work-no-changes-count":1,"work-suggested-action":"recheck the external blocker and move status to open when cleared"} {"acceptance":"tablespec validate \u003csplit-table-dir\u003e validates that table (nonzero on invalid); 'All 0 tables passed' is impossible when the target contains a table.yaml.","created_at":"2026-06-12T02:16:38.634412063Z","description":"Site rewrite verification 2026-06-12: the CLI validate single-table branch keys on schema.yaml but split format uses table.yaml, so a single table dir falls into pipeline mode and reports 'All 0 tables passed' (exit 0). Vacuous pass = false confidence. Should detect table.yaml dirs and validate them.","id":"tablespec-b476109a","issue_type":"bug","labels":["kind:bug","area:cli","area:validation"],"owner":"erik","priority":2,"schema_version":1,"status":"closed","title":"tablespec validate on a single split table dir silently validates nothing","updated_at":"2026-06-12T16:33:48.084962514Z"} {"acceptance":"1. TestHelixDocsUseCanonicalDatabricksDialectGuidance: add a docs traceability regression that scans `docs/helix/03-test/conformance-acceptance.md` and related Databricks helix references for canonical `dialect=\"databricks\"` guidance.\\n2. TestHelixDocsAvoidSparkOnlyMessaging: assert helix docs do not tell Databricks users to use only `dialect=\"spark\"` without the alias explanation.\\n3. go test ./...\\n4. lefthook run pre-commit.","closing_commit_sha":"ad838e8b7c6d9711b54291895b08bca60507b822","created_at":"2026-06-08T14:55:59.650831628Z","description":"PROBLEM: The helix conformance docs already describe Databricks dialect behavior, but that decision is not reflected consistently in the user-facing examples and traceability checks. ROOT CAUSE: `docs/helix/03-test/conformance-acceptance.md:85` and `docs/helix/03-test/conformance-acceptance.md:109` discuss Databricks dialect behavior without tying it back to the canonical public alias guidance used elsewhere. PROPOSED FIX: Update the helix conformance docs and their traceability expectations so they consistently say `dialect=\"databricks\"` is accepted for Databricks compile UX, while clarifying that generated casts may normalize to Spark-family SQL when the emitted SQL is identical. NON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No broad documentation rewrite outside Databricks dialect guidance. GOVERNING ARTIFACTS: `docs/guide/bootstrap.md:10`; `README.md:139`; `docs/helix/03-test/conformance-acceptance.md:109`; `scripts/run_integration_tests_databricks.ipynb`. DEPENDENCIES: `tablespec-ed74497c`.","events_attachment":"tablespec-b50b6f67/events.jsonl","id":"tablespec-b50b6f67","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"parent":"tablespec-0fb0d1c2","priority":0,"schema_version":1,"session_id":"eb-4ea7415a","status":"closed","title":"Align helix conformance docs with Databricks dialect guidance","updated_at":"2026-06-08T20:18:39.087381651Z"} {"acceptance":"1. Specs/docs explicitly state that production runs installed pipeline JSON artifacts and installed wheels, not source-time Python orchestration.\n2. The development pipeline has a documented command that builds wheel artifacts for installation and produces or verifies the pipeline JSON files expected by production.\n3. A test or build command such as uv build plus a JSON artifact validation test passes and is named in the implementation notes.\n4. Bootstrap/compile docs describe their output as inputs to the installable production pipeline contract rather than the production runtime itself.\n5. Any Databricks try-it-out instructions distinguish development bootstrap from production install/run.","closing_commit_sha":"45ab8f38ee1f76936285006c873590f3835ab5ad","created_at":"2026-06-08T00:18:50.429673685Z","description":"Align development and production pipeline semantics around installable pipeline artifacts. The production pipeline is intended to run from installed pipelines stored as JSON files, not from ad hoc source-time reconstruction or notebook-local Python composition. The development pipeline should therefore build wheel artifacts for installation and produce or validate the JSON pipeline definitions that production installs/runs. This is related to the bootstrap/compile facade work but distinct: bootstrap may author or compile artifacts, while production should consume installed JSON pipeline artifacts plus installed tablespec/package wheels.\n\nCurrent context:\n- Existing compile/runtime docs emphasize committed artifacts and runtime not re-deriving from UMF.\n- The desired production contract is stronger: installed pipelines live as JSON files, and the dev path builds wheels for installation.\n- Avoid a Databricks UX where users copy inline Python orchestration into production. The user-facing flow should make build/install/run boundaries explicit.\n\nIn-scope files:\n- docs/helix PRD/design/build docs that define production vs development pipeline boundaries\n- scripts or build tooling that package wheels and/or pipeline JSON artifacts\n- tests that verify the build artifacts expected by production exist and are installable/parseable\n- bootstrap/compile docs only where needed to describe handoff to production artifacts\n\nOut-of-scope for this bead:\n- Implementing the one-shot Databricks bootstrap facade itself\n- Removing inline YAML UMF support\n- Replacing the runtime backbone wholesale","events_attachment":"tablespec-b9dec718/events.jsonl","id":"tablespec-b9dec718","issue_type":"task","labels":["area:pipeline","area:packaging","area:runtime","kind:architecture","ac-quality:needs-refinement"],"priority":0,"schema_version":1,"session_id":"eb-d0adbfa2","spec-id":"FEAT-026","status":"closed","title":"Align dev pipeline with installed JSON pipeline artifacts and wheels","updated_at":"2026-06-08T00:57:52.145087747Z"} @@ -90,7 +90,7 @@ {"acceptance":"A recorded convention (principles.md or concerns.md note) names the canonical status set; US-022 and US-025 status lines match it.","created_at":"2026-06-11T00:23:44.199375946Z","description":"Spec audit 2026-06-10: all 29 FEATs and 35/37 stories use Status: Implemented; 2 stories use 'Done (...)'. Template enums are draft|in_review|approved|superseded (feature-specification meta.yml) and Draft|Review|Approved (user-stories template). Decide the canonical post-build status value (e.g. add 'implemented' to the project's accepted enum, or map to 'approved') and normalize US-022/US-025 free-text statuses.","id":"tablespec-c1e598f1","issue_type":"task","labels":["helix","spec","decision"],"priority":2,"resolution":"DECIDED 2026-06-10 (operator): map to template enums. FEAT/US statuses normalized Implemented→Approved (66 files); registry rows record delivery stage Built; test_governing_docs_alignment.py updated to assert Approved.","schema_version":1,"status":"closed","title":"DECISION: post-build status vocabulary for FEAT/US frontmatter","updated_at":"2026-06-11T00:56:02.34713056Z"} {"acceptance":"Every story has the 7 required sections, stable US-\u003cn\u003e-AC\u003cm\u003e Given/When/Then ACs, and concrete test scenarios naming specific values.","created_at":"2026-06-11T00:23:44.344398971Z","description":"Spec audit 2026-06-10: US-001..020 miss 5 of 7 required sections (Context, Walkthrough, Edge Cases, Test Scenarios, Dependencies); US-001..010 have no stable US-\u003cn\u003e-ACm IDs; US-011..020 ACs are not Given/When/Then. US-027..036 have only 2 thin ACs each covering 3-6 FR sub-requirements with placeholder test scenarios. Exemplars: US-021..026, US-037.","id":"tablespec-c3471969","issue_type":"task","labels":["helix","spec","backfill"],"owner":"erik","priority":2,"schema_version":1,"status":"closed","title":"Backfill US-001..020 template sections and AC IDs; thicken US-027..036 ACs","updated_at":"2026-06-12T17:43:25.835982577Z"} {"acceptance":"pytest green incl. new unit tests per consumer; a spec with EMBEDDING(1024) round-trips, compiles to ARRAY\u003cFLOAT\u003e DDL + ArrayType pyspark + JSON schema; GX suite contains the dimensionality expectation; dimension mismatch fails validation; existing corpus byte-identical.","created_at":"2026-06-12T16:49:59.863931435Z","description":"ADR-016 (Accepted): dimensioned EMBEDDING logical type -\u003e ARRAY\u003cFLOAT\u003e (Spark SQL/Delta), ArrayType(FloatType()) (PySpark), array-of-number (JSON Schema). Touch: models/umf.py:509-511 type pattern + dimension field, type_mappings.py, schemas/generators.py, gx_baseline.py (dimensionality expectation; %16 Vector-Search advisory non-blocking; exclude from string-shape checks), sample_data (seeded unit vectors), compatibility.py/type_lattice.py (EMBEDDING compatible only with same-dimension EMBEDDING), profiling passthrough, umf.schema.json. Per FEAT-032 EMB-01..09.","id":"tablespec-c5f57c11","issue_type":"task","labels":["feat-032","area:models","area:types","kind:feature"],"owner":"erik","priority":1,"schema_version":1,"status":"closed","title":"Implement EMBEDDING(dim) type across the type system (FEAT-032 EMB-)","updated_at":"2026-06-12T17:46:28.040478934Z"} -{"acceptance":"1. TestDatabricksCompileArtifactsStateNormalizationDecision: assert the implementation notes or generated metadata/comments state the decision that public dialect=\"databricks\" is accepted and Spark-family SQL emitters may normalize to spark internally because cast SQL is identical.\n2. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n3. TestGoGate: `go test ./...`\n4. TestLefthookGate: `lefthook run pre-commit`","created_at":"2026-06-08T18:22:28.923233689Z","description":"PROBLEM: The implementation notes, comments, or generated metadata do not clearly explain why public dialect=\"databricks\" may be normalized internally by Spark-family SQL emitters, leaving the normalization behavior easy to misread as unsupported dialect handling.\nROOT CAUSE: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84 is the governing compile-orchestrator artifact, but the implementation notes and emitted metadata/comments do not state that public dialect=\"databricks\" is accepted while Spark-family emitters may normalize to spark internally because cast SQL is identical.\nPROPOSED FIX: Update implementation notes, comments, or generated metadata and bootstrap regression coverage to explicitly state the normalization decision: databricks remains accepted at the public contract boundary, and Spark-family SQL emitters may normalize internally to spark because the generated cast SQL is identical.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events":[{"actor":"ddx","body":"{\"resolved_provider\":\"sindri\",\"resolved_model\":\"dflash\",\"route_reason\":\"policy=cheap; score=135.0\",\"fallback_chain\":[],\"requested_min_power\":5}","created_at":"2026-06-08T23:04:19.404696255Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=sindri model=dflash reason=policy=cheap; score=135.0"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T203946-dfb4f30c\",\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"policy=cheap; score=135.0\",\"input_tokens\":778463,\"output_tokens\":6780,\"total_tokens\":785243,\"cost_usd\":0,\"duration_ms\":7004413,\"exit_code\":1}","created_at":"2026-06-08T23:04:19.435583756Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=785243 model=dflash"},{"actor":"ddx","body":"{\"actual_harness\":\"fiz\",\"actual_model\":\"dflash\",\"actual_power\":0,\"actual_provider\":\"sindri\",\"attempt_id\":\"20260608T203946-dfb4f30c\",\"bead_id\":\"tablespec-c65a49de\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T23:04:26.172766253Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard model=dflash harness=fiz"},{"actor":"erik","body":"{\"base_rev\":\"fdc7bdbe4faa6e08b34c658096b28203f1f1cb2f\",\"classification\":\"routing\",\"detail\":\"agent: provider error: openai: POST \\\"http://sindri:8080/v1/chat/completions\\\": 400 Bad Request {\\\"message\\\":\\\"prompt + max_tokens exceeds context window\\\",\\\"type\\\":\\\"invalid_request_error\\\"}\",\"rationale\":\"Attempt failed before implementation because the selected provider/model route rejected the request with context_overflow: prompt + max_tokens exceeded the model context window. This is a routing/capability mismatch, not evidence of a bead defect.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"fdc7bdbe4faa6e08b34c658096b28203f1f1cb2f\",\"session_id\":\"eb-18c13fca\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T23:04:52.208727818Z","kind":"bead-quality.triage","source":"ddx work","summary":"routing: release_claim_retry"},{"actor":"erik","body":"agent: provider error: openai: POST \"http://sindri:8080/v1/chat/completions\": 400 Bad Request {\"message\":\"prompt + max_tokens exceeds context window\",\"type\":\"invalid_request_error\"}\npowerClass=standard\ndecision_audit={\"failure_class\":\"routing\",\"retry_action\":\"retry\",\"escalation_count\":0,\"requested_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"profile\":\"cheap\",\"routing_intent_source\":\"default\",\"inferred_power_class\":\"standard\",\"requested_power_class\":\"standard\"},\"actual_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"default\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=fdc7bdbe4faa6e08b34c658096b28203f1f1cb2f\nbase_rev=fdc7bdbe4faa6e08b34c658096b28203f1f1cb2f\noutcome_reason=routing","created_at":"2026-06-08T23:04:52.223330465Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"erik","body":"{\"decision\":\"warn\",\"decision_source\":\"pre_claim_intake\",\"detail\":\"readiness check timed out after 5m0s (tablespec-c65a49de)\",\"fingerprint\":\"5de7b8ac14ec7cc443d4124ca65154c9cd7d86966f2771ef34df4f39db9e48a0\",\"policy_mode\":\"warn-only\",\"reason\":\"timeout\",\"rule_id\":\"pre_claim_intake.timeout\",\"suggested_action\":\"revise the rewrite so it preserves every explicit commitment\",\"warning_fingerprint\":\"5de7b8ac14ec7cc443d4124ca65154c9cd7d86966f2771ef34df4f39db9e48a0\"}","created_at":"2026-06-08T23:09:53.833253303Z","kind":"intake.warn","source":"ddx work","summary":"timeout"},{"actor":"ddx","body":"{\"resolved_provider\":\"sindri\",\"resolved_model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"fallback_chain\":[],\"requested_min_power\":5}","created_at":"2026-06-08T23:29:00.339525219Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=sindri model=dflash reason=policy=cheap; score=35.0"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T231157-4e2fe723\",\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"input_tokens\":120434,\"output_tokens\":731,\"total_tokens\":121165,\"cost_usd\":0,\"duration_ms\":1021829,\"exit_code\":1}","created_at":"2026-06-08T23:29:00.353593203Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=121165 model=dflash"},{"actor":"ddx","body":"{\"actual_harness\":\"fiz\",\"actual_model\":\"dflash\",\"actual_power\":0,\"actual_provider\":\"sindri\",\"attempt_id\":\"20260608T231157-4e2fe723\",\"bead_id\":\"tablespec-c65a49de\",\"estimated_difficulty\":\"\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"default\"}","created_at":"2026-06-08T23:29:01.575403614Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=default powerClass=standard model=dflash harness=fiz"},{"actor":"erik","body":"{\"base_rev\":\"170ce8fe33100a8e107a4f4046840877d7839794\",\"classification\":\"routing\",\"detail\":\"agent: provider error: openai: POST \\\"http://sindri:8080/v1/chat/completions\\\": 400 Bad Request {\\\"message\\\":\\\"prompt + max_tokens exceeds context window\\\",\\\"type\\\":\\\"invalid_request_error\\\"}\",\"rationale\":\"Attempt failed before implementation because the selected sindri/dflash route rejected the request with context_overflow: prompt plus max_tokens exceeded the model context window. This is a provider/model capability mismatch, not a bead defect or code failure.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"170ce8fe33100a8e107a4f4046840877d7839794\",\"session_id\":\"eb-8086333d\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T23:29:24.801935456Z","kind":"bead-quality.triage","source":"ddx work","summary":"routing: release_claim_retry"},{"actor":"erik","body":"agent: provider error: openai: POST \"http://sindri:8080/v1/chat/completions\": 400 Bad Request {\"message\":\"prompt + max_tokens exceeds context window\",\"type\":\"invalid_request_error\"}\npowerClass=standard\ndecision_audit={\"failure_class\":\"routing\",\"retry_action\":\"retry\",\"escalation_count\":0,\"requested_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"profile\":\"cheap\",\"routing_intent_source\":\"default\",\"inferred_power_class\":\"standard\",\"requested_power_class\":\"standard\"},\"actual_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"default\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=170ce8fe33100a8e107a4f4046840877d7839794\nbase_rev=170ce8fe33100a8e107a4f4046840877d7839794\noutcome_reason=routing","created_at":"2026-06-08T23:29:24.821641726Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"ddx","body":"{\"resolved_provider\":\"sindri\",\"resolved_model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"fallback_chain\":[],\"requested_min_power\":5}","created_at":"2026-06-08T23:52:06.408910702Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=sindri model=dflash reason=policy=cheap; score=35.0"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T233411-13d50c29\",\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"policy=cheap; score=35.0\",\"input_tokens\":134604,\"output_tokens\":1014,\"total_tokens\":135618,\"cost_usd\":0,\"duration_ms\":1073208,\"exit_code\":1}","created_at":"2026-06-08T23:52:06.427855153Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=135618 model=dflash"},{"actor":"ddx","body":"{\"actual_harness\":\"fiz\",\"actual_model\":\"dflash\",\"actual_power\":0,\"actual_provider\":\"sindri\",\"attempt_id\":\"20260608T233411-13d50c29\",\"bead_id\":\"tablespec-c65a49de\",\"estimated_difficulty\":\"medium\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"readiness\"}","created_at":"2026-06-08T23:52:07.906940353Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=readiness difficulty=medium powerClass=standard model=dflash harness=fiz"},{"actor":"erik","body":"{\"base_rev\":\"425c49e098238c8afd57555cc2587d53bcf7c2c5\",\"classification\":\"routing\",\"detail\":\"agent: provider error: openai: POST \\\"http://sindri:8080/v1/chat/completions\\\": 400 Bad Request {\\\"message\\\":\\\"prompt + max_tokens exceeds context window\\\",\\\"type\\\":\\\"invalid_request_error\\\"}\",\"rationale\":\"Attempt failed before implementation because sindri/dflash rejected the request with context_overflow: prompt plus max_tokens exceeded the model context window. The repeated failures with unchanged result_rev indicate a route capability mismatch, not a bead defect or code/test failure.\",\"recommended_action\":\"release_claim_retry\",\"result_rev\":\"425c49e098238c8afd57555cc2587d53bcf7c2c5\",\"session_id\":\"eb-bd2a0ab6\",\"status\":\"execution_failed\",\"suggested_amendments\":[],\"suggested_followup_beads\":[]}","created_at":"2026-06-08T23:52:40.123850771Z","kind":"bead-quality.triage","source":"ddx work","summary":"routing: release_claim_retry"},{"actor":"erik","body":"agent: provider error: openai: POST \"http://sindri:8080/v1/chat/completions\": 400 Bad Request {\"message\":\"prompt + max_tokens exceeds context window\",\"type\":\"invalid_request_error\"}\npowerClass=standard\ndecision_audit={\"failure_class\":\"routing\",\"retry_action\":\"retry\",\"escalation_count\":0,\"requested_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"profile\":\"cheap\",\"routing_intent_source\":\"readiness\",\"estimated_difficulty\":\"medium\",\"inferred_power_class\":\"standard\",\"requested_power_class\":\"standard\"},\"actual_route\":{\"harness\":\"fiz\",\"provider\":\"sindri\",\"model\":\"dflash\",\"route_reason\":\"readiness\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=425c49e098238c8afd57555cc2587d53bcf7c2c5\nbase_rev=425c49e098238c8afd57555cc2587d53bcf7c2c5\noutcome_reason=routing","created_at":"2026-06-08T23:52:40.149460833Z","kind":"execute-bead","source":"ddx work","summary":"execution_failed"},{"actor":"ddx","body":"{\"resolved_provider\":\"codex\",\"resolved_model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"fallback_chain\":[],\"requested_min_power\":5}","created_at":"2026-06-09T00:40:51.958077993Z","kind":"routing","source":"legacy agent execute-bead","summary":"provider=codex model=gpt-5.4-mini reason=explicit_pin_discovery_unavailable"},{"actor":"ddx","body":"{\"attempt_id\":\"20260608T235728-9075962f\",\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"explicit_pin_discovery_unavailable\",\"input_tokens\":2030874,\"output_tokens\":25536,\"total_tokens\":2056410,\"cost_usd\":0,\"duration_ms\":388687,\"exit_code\":0}","created_at":"2026-06-09T00:40:52.025492365Z","kind":"cost","source":"legacy agent execute-bead","summary":"tokens=2056410 model=gpt-5.4-mini"},{"actor":"ddx","body":"{\"actual_harness\":\"codex\",\"actual_model\":\"gpt-5.4-mini\",\"actual_power\":0,\"actual_provider\":\"\",\"attempt_id\":\"20260608T235728-9075962f\",\"bead_id\":\"tablespec-c65a49de\",\"estimated_difficulty\":\"medium\",\"rejected_route_pins\":null,\"requested_power_class\":\"standard\",\"requested_profile\":\"cheap\",\"routing_intent_degraded\":false,\"routing_intent_note\":\"\",\"routing_intent_source\":\"readiness\"}","created_at":"2026-06-09T00:41:02.125862928Z","kind":"execution-routing-intent","source":"ddx work","summary":"source=readiness difficulty=medium powerClass=standard model=gpt-5.4-mini harness=codex"},{"actor":"erik","body":"status=proposed\nreason=The acceptance gate requires `go test ./...`, but this worktree contains no Go module or Go packages, so the command cannot execute here without repository changes outside the bead scope.\nsuggested_action=review and accept, split, block, or cancel this proposed work","created_at":"2026-06-09T00:41:02.201044536Z","kind":"no_changes_operator_required","source":"ddx work","summary":"no_changes_operator_required"},{"actor":"erik","body":"no_changes\npowerClass=standard\nrationale: status: proposed\nreason: The acceptance gate requires `go test ./...`, but this worktree contains no Go module or Go packages, so the command cannot execute here without repository changes outside the bead scope.\ndecision_audit={\"failure_class\":\"no_changes\",\"retry_action\":\"retry\",\"escalation_count\":1,\"requested_route\":{\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"profile\":\"cheap\",\"routing_intent_source\":\"readiness\",\"estimated_difficulty\":\"medium\",\"inferred_power_class\":\"standard\",\"requested_power_class\":\"standard\"},\"actual_route\":{\"harness\":\"codex\",\"model\":\"gpt-5.4-mini\",\"route_reason\":\"readiness\"},\"review_status\":\"skipped\",\"review_skip_reason\":\"review_not_configured\",\"review_classification\":\"review_skipped\",\"land_status\":\"not_landed\",\"reconcile_status\":\"not_applicable\"}\nresult_rev=113e0cac9176bd7df6f9b24c4ce4116b625f9b30\nbase_rev=113e0cac9176bd7df6f9b24c4ce4116b625f9b30\noutcome_reason=no_changes","created_at":"2026-06-09T00:41:02.2290019Z","kind":"execute-bead","source":"ddx work","summary":"no_changes"}],"id":"tablespec-c65a49de","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"needs-human-reason":"The acceptance gate requires `go test ./...`, but this worktree contains no Go module or Go packages, so the command cannot execute here without repository changes outside the bead scope.","needs-human-since":"2026-06-09T00:41:02Z","needs-human-source":"ddx work","needs-human-suggested-action":"review and accept, split, block, or cancel this proposed work","needs-human-summary":"no_changes requested operator attention","parent":"tablespec-943b21a5","priority":0,"schema_version":1,"status":"proposed","title":"Document Spark-family normalization for databricks emitters","updated_at":"2026-06-09T00:41:02.247259532Z","work-last-detail":"The acceptance gate requires `go test ./...`, but this worktree contains no Go module or Go packages, so the command cannot execute here without repository changes outside the bead scope.","work-last-status":"no_changes_operator_required","work-no-changes-count":1,"work-suggested-action":"review and accept, split, block, or cancel this proposed work"} +{"acceptance":"1. TestDatabricksCompileArtifactsStateNormalizationDecision: compile.py + dialects.normalize_cast_dialect document/prove public dialect=databricks normalizes to spark for identical cast SQL.\n2. TestPytestGate: `uv run pytest tests/docs/test_dialect_contract.py tests/unit/test_bootstrap.py`\n3. TestPreCommitGate: pre-commit / CI pre-commit job.\nNote: `go test ./...` is not a gate for this pure-Python repository.","created_at":"2026-06-08T18:22:28.923233689Z","description":"PROBLEM: The implementation notes, comments, or generated metadata do not clearly explain why public dialect=\"databricks\" may be normalized internally by Spark-family SQL emitters, leaving the normalization behavior easy to misread as unsupported dialect handling.\nROOT CAUSE: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84 is the governing compile-orchestrator artifact, but the implementation notes and emitted metadata/comments do not state that public dialect=\"databricks\" is accepted while Spark-family emitters may normalize to spark internally because cast SQL is identical.\nPROPOSED FIX: Update implementation notes, comments, or generated metadata and bootstrap regression coverage to explicitly state the normalization decision: databricks remains accepted at the public contract boundary, and Spark-family SQL emitters may normalize internally to spark because the generated cast SQL is identical.\nNON-SCOPE: One-shot bootstrap facade implementation. Production pipeline JSON/wheel packaging contract. Inline UMF format cleanup. No real Databricks workspace execution beyond existing opt-in tiers. GOVERNING ARTIFACTS: docs/helix/01-frame/features/FEAT-026-compile-orchestrator-bootstrap.md:84; docs/helix/03-test/conformance-acceptance.md:49; docs/helix/03-test/conformance-acceptance.md:85; docs/helix/03-test/conformance-acceptance.md:109. DEPENDENCIES: parent bead tablespec-ed74497c; no additional dependencies.","events_attachment":"tablespec-c65a49de/events.jsonl","id":"tablespec-c65a49de","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:refined"],"owner":"erik","parent":"tablespec-943b21a5","priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Document Spark-family normalization for databricks emitters","updated_at":"2026-07-23T00:25:57.310822858Z","work-last-detail":"The acceptance gate requires `go test ./...`, but this worktree contains no Go module or Go packages, so the command cannot execute here without repository changes outside the bead scope.","work-last-status":"no_changes_operator_required","work-no-changes-count":1,"work-suggested-action":"review and accept, split, block, or cancel this proposed work"} {"acceptance":"Each ADR has the template sections; no in-place post-acceptance tracker edits remain (history preserved via supersession/status annotations).","created_at":"2026-06-11T00:23:44.419722289Z","description":"Spec audit 2026-06-10: ADR-001..008 predate the catalog template: prose Status instead of header table, no Alternatives section (blocking alternatives_evaluated check), missing Risks/Validation/Supersession/Concern Impact/References. ADR-006 has alternatives content inline needing only heading restructure. ADR-007/008 contain post-acceptance status edits that should move to supersession notes. Exemplars: ADR-009..013.","id":"tablespec-cb798660","issue_type":"task","labels":["helix","spec","backfill"],"owner":"erik","priority":3,"schema_version":1,"status":"closed","title":"Backfill ADR-001..008 to current ADR template (Alternatives, Risks, Validation)","updated_at":"2026-06-12T17:02:16.419944093Z"} {"acceptance":"1. Child bead for FEAT-024 profiler candidate inference exists and is linked under this parent.\n2. Child bead for FEAT-026 bootstrap/compile sidecar and auto-promotion policy exists and depends on the profiler child.\n3. Child bead for FEAT-007 compound uniqueness validation support/quarantine exists and depends on the profiler child.\n4. Each child bead includes command-based acceptance criteria with named tests and scope boundaries.","created_at":"2026-06-08T04:18:43.35752831Z","description":"Parent epic for candidate key inference from native Spark profiles. Current behavior: NativeSparkProfiler computes row count, completeness, cardinality, numeric/string stats, quantiles, values, and patterns, but it does not detect primary keys. ProfileToGxMapper may emit approximate single-column uniqueness expectations based on cardinality ratio; that is validation-rule enrichment, not authoritative primary-key inference.\n\nGoal: add advisory key-candidate inference without treating guesses as authoritative UMF keys by default. Split implementation across the owning specs: FEAT-024 owns profiler models/inference and mapper dedup, FEAT-026 owns bootstrap/compile sidecar artifacts and auto-promotion provenance, and FEAT-007 owns compound uniqueness execution or explicit non-emission when unsupported.\n\nDesign constraints accepted from review:\n- Candidate mode is advisory and must not mutate persisted UMF snapshots.\n- Auto-promotion is explicitly configured and is a behavior-changing write to UMF.primary_key.\n- Compound uniqueness is only considered validation-supported when executable by the native executor, not merely schema-allowed.\n- Candidate ordering, scoring, and serialized sidecars must be deterministic.\n- Exact verification must use Spark-SQL/DataFrame operations that are Connect/serverless safe.\n\nChild beads should be executable independently and cold-readable. Do not implement this parent directly.","events":[{"actor":"","body":"closed_because: all_children_terminal\ntotal_children: 3","created_at":"2026-06-09T20:47:18.126777759Z","kind":"epic_auto_close","source":"Store.Close.walkUpClosureCandidate","summary":"auto-closed: all children reached terminal state"}],"id":"tablespec-cc4f665b","issue_type":"epic","labels":["area:profiling","area:bootstrap","area:validation","kind:feature"],"priority":1,"schema_version":1,"spec-id":"FEAT-024","status":"closed","title":"Add native-profiler candidate key inference","updated_at":"2026-06-09T20:47:18.129298422Z"} {"acceptance":"1. TestKeyCandidateModels::test_key_candidate_models_are_json_serializable verifies KeyCandidate and KeyCandidateEvidence serialize with every documented evidence field present, candidate kind constrained to primary_key_candidate or unique_constraint_candidate, score bounded in [0, 1], and DataFrameProfile exposes key_candidates without breaking existing columns/num_records construction.\n2. TestKeyCandidateModels::test_dataframe_profile_default_key_candidates_isolated verifies DataFrameProfile.key_candidates defaults to an empty list and does not share mutable list state between profile instances.\n3. TestQualityGates::test_key_candidate_models_go_test_gate documents and passes go test ./... or records operator_required when no Go module/toolchain exists.\n4. TestQualityGates::test_key_candidate_models_lefthook_gate documents and passes lefthook run pre-commit or records operator_required when lefthook is unavailable.\n5. TestVerificationCommands::test_key_candidate_models_pytest_gate documents and passes uv run pytest tests/unit/test_native_profiler_key_candidates.py tests/unit/test_profiler_connect_sail.py tests/unit -k gx_expectation.","closing_commit_sha":"d16c665ef63409828d9179ed5376fe8bce6b5eee","created_at":"2026-06-09T04:53:43.812978901Z","description":"PROBLEM: DataFrameProfile has no typed profile-level representation for advisory primary-key or unique-key candidates, so later inference work has nowhere JSON-serializable to put evidence without conflating advisory candidates with authoritative UMF.primary_key or unique_constraints.\n\nROOT CAUSE: src/tablespec/profiling/types.py:53 defines DataFrameProfile with only num_records and columns; src/tablespec/profiling/types.py has no KeyCandidate or KeyCandidateEvidence model.\n\nPROPOSED FIX: Add typed dataclass models KeyCandidate and KeyCandidateEvidence in src/tablespec/profiling/types.py. Add key_candidates: list[KeyCandidate] to DataFrameProfile with default_factory=list while preserving existing DataFrameProfile(num_records=..., columns=...) construction. Models must serialize through dataclasses.asdict/json-compatible primitives. Candidate kind must be constrained to primary_key_candidate or unique_constraint_candidate. Evidence fields must include row_count, columns, null_count_by_column, exact_distinct_count, approximate_distinct_count_by_column, distinct_ratio, completeness_by_column, verified_exact, nullable, minimal, subset_unique, score, score_components, name_hints, type_hints, penalties, verification_pass_count, verification_query_count, and reason. Score must be bounded in [0, 1].\n\nGOVERNING ARTIFACT: parent bead tablespec-cc4f665b.\n\nDEPENDENCY ID: tablespec-cc4f665b.\n\nNON-SCOPE: Writing sidecar files or extending manifest layout; tracked by FEAT-026 child. Mutating UMF.primary_key or unique_constraints. Making sample data, dbt, or LDP consume inferred candidates. Implementing compound uniqueness execution in the validator; tracked by FEAT-007 child.\n\nVERIFICATION REQUIREMENT: uv run pytest tests/unit/test_native_profiler_key_candidates.py tests/unit/test_profiler_connect_sail.py tests/unit -k gx_expectation. Also run go test ./... or record operator_required when no Go module/toolchain exists, and lefthook run pre-commit or record operator_required when lefthook is unavailable.","id":"tablespec-ce4a8ebc","issue_type":"task","labels":["area:profiling","kind:feature","ac-quality:refined","parent:tablespec-cc4f665b","component:profile-models"],"owner":"erik","parent":"tablespec-a727e762","priority":0,"schema_version":1,"status":"closed","title":"Add JSON-serializable advisory key-candidate profile models","updated_at":"2026-06-09T20:29:54.71566449Z"} @@ -99,14 +99,14 @@ {"acceptance":"1. TestNativeProfilerSingleColumnKeys::test_native_profiler_single_column_exact_key_candidate uses a fixture with \u003e=100 rows, or explicitly overrides key_min_rows, and produces exactly one verified_exact primary_key_candidate for a non-null unique id with every documented evidence field present and score in [0, 1].\n2. TestNativeProfilerSingleColumnKeys::test_native_profiler_nullable_unique_is_not_pk verifies a nullable unique column produces no primary_key_candidate and is represented as unique_constraint_candidate or advisory evidence with nullable=true.\n3. TestNativeProfilerSingleColumnKeys::test_native_profiler_key_min_rows_prevents_noisy_inference verifies defaults produce no candidates below key_min_rows and an explicit key_min_rows override makes candidates non-empty on the same deterministic fixture.\n4. TestNativeProfilerSingleColumnKeys::test_single_column_candidate_ordering_is_total_and_stable verifies ordering by score descending, key width ascending, and column-name tuple ascending for tied or near-tied candidates.\n5. TestNativeProfilerSingleColumnKeys::test_single_column_exact_verification_uses_connect_safe_dataframe_operations verifies inference does not call RDDs or classic-only SparkContext APIs.\n6. TestQualityGates::test_single_column_go_test_gate documents and passes go test ./... or records operator_required when no Go module/toolchain exists.\n7. TestQualityGates::test_single_column_lefthook_gate documents and passes lefthook run pre-commit or records operator_required when lefthook is unavailable.\n8. Verification command passes: uv run pytest tests/unit/test_native_profiler_key_candidates.py tests/unit/test_profiler_connect_sail.py tests/unit -k gx_expectation.","closing_commit_sha":"1dbd5405e41371730429a8cb3ddfd658b6b658d4","created_at":"2026-06-09T04:49:35.160917449Z","description":"PROBLEM: NativeSparkProfiler computes per-column completeness and approximate cardinality, but it does not promote high-confidence single-column keys into advisory candidates. Users cannot distinguish a verified exact non-null unique identifier from the existing approximate uniqueness heuristic.\n\nROOT CAUSE: src/tablespec/profiling/native_profiler.py:165 batches completeness and approximate cardinality signals, src/tablespec/profiling/native_profiler.py:198 builds ColumnProfile objects, and src/tablespec/profiling/native_profiler.py:228 returns DataFrameProfile without any key candidate scoring, exact verification, nullable handling, or key_min_rows guard.\n\nPROPOSED FIX: When infer_key_candidates=True and row_count \u003e= key_min_rows, derive single-column candidate prefilters from existing completeness and approximate distinct signals, deterministic name/type hints, and penalties. Exact-verify only bounded prefiltered columns using Spark SQL/DataFrame aggregations that are Spark Connect-safe and do not use RDDs or SparkContext APIs. Emit primary_key_candidate only for non-null exact unique columns; emit unique_constraint_candidate or advisory nullable evidence for nullable exact-unique columns. Score deterministically in [0, 1], populate all evidence fields, and order candidates by score descending, key width ascending, then column-name tuple ascending.\n\nGOVERNING ARTIFACT: parent bead tablespec-cc4f665b.\n\nDEPENDENCY ID: tablespec-cc4f665b.\n\nNON-SCOPE: Composite key search and subset minimality beyond single-column minimal=true. Writing sidecar files or extending manifest layout; tracked by FEAT-026 child. Mutating UMF.primary_key or unique_constraints. Making sample data, dbt, or LDP consume inferred candidates. Implementing compound uniqueness execution in the validator; tracked by FEAT-007 child.","events_attachment":"tablespec-d73e83ed/events.jsonl","id":"tablespec-d73e83ed","issue_type":"task","labels":["area:profiling","kind:feature","ac-quality:refined","parent:tablespec-cc4f665b"],"parent":"tablespec-29002b40","priority":0,"schema_version":1,"session_id":"eb-0efae538","status":"closed","title":"Infer exact single-column advisory key candidates","updated_at":"2026-06-09T05:06:31.524203833Z"} {"acceptance":"CLAUDE.md project-structure section lists every src/tablespec subpackage with a one-liner; optional-extras section covers [spark], [duckdb], [tui].","created_at":"2026-06-11T00:24:15.992352406Z","description":"Implementation-surface audit 2026-06-10: CLAUDE.md covers ~1/3 of src/tablespec — omits core/, dbt/, ldp/, e2e/, quality/, sample_data/, authoring/, inference/, formatting/, the Typer CLI, the TUI, and change-management/compatibility modules. The stale deequ_mapper.py reference was fixed 2026-06-10; the rest needs a structured refresh so agent guidance matches the v3.0 compiler architecture.","id":"tablespec-d88dcb4a","issue_type":"chore","labels":["docs","chore"],"owner":"erik","priority":3,"schema_version":1,"status":"closed","title":"Refresh repo CLAUDE.md module map to current architecture","updated_at":"2026-06-12T16:50:25.807791183Z"} {"acceptance":"Both notebooks committed under notebooks/kaggle-demo/ with README; Databricks job run green (scorecard PASS) with run id recorded; US-044 ACs checked with evidence.","closing_commit_sha":"327ccb133bc92c4c36fdf333f96c590fb1a00228","created_at":"2026-06-12T16:49:59.779301749Z","description":"FEAT-031 / US-044, shipped code only: notebooks/kaggle-demo/ pair mirroring northwind-demo — 01 acquires a Kaggle/shared CSV dataset (widget-swappable; default NYC Airbnb AB_NYC_2019.csv), 02 lands delimited raw, profiles via NativeSparkProfiler, maps to UMF via SparkToUmfMapper, validates, exports workbook, generates artifacts, staged validation scorecard. Prove on dbw-dev-eus2 like Northwind.","events_attachment":"tablespec-da6ee32b/events.jsonl","id":"tablespec-da6ee32b","issue_type":"task","labels":["area:demo","feat-031","databricks"],"parent":"tablespec-ef91646f","priority":2,"schema_version":1,"session_id":"eb-15e2d296","status":"closed","title":"Kaggle flat-file onboarding demo notebooks (US-044)","updated_at":"2026-06-14T02:20:21.408925703Z"} -{"acceptance":"Every acceptance criterion in US-001 through US-020 has a stable US-NNN-ACx ID; each new AC ID has a matching @covers citation or is explicitly marked unimplemented with a follow-up bead; helix_align_check --strict remains clean; the review report explains any intentionally untested acceptance criteria.","created_at":"2026-06-07T20:59:18.686298395Z","description":"US-001 through US-020 still use legacy unchecked acceptance bullets without stable US-NNN-ACx IDs. The Helix align checker currently reports 52/52 cited ACs, but those legacy bullets are not machine-addressable and are effectively outside the coverage matrix.","events":[{"actor":"erik","body":"{\"ac_map\":[{\"parent_ac\":\"Implement the first bounded slice of the parent bead.\",\"coverage\":\"covered by child 1: Normalize legacy user-story acceptance criteria: part 1\"},{\"parent_ac\":\"Implement the remaining bounded slice of the parent bead.\",\"coverage\":\"covered by child 2: Normalize legacy user-story acceptance criteria: part 2\"}],\"child_ids\":[\"tablespec-b474ae20\",\"tablespec-9fad11d8\"],\"rationale\":\"deterministic fallback split after agent decomposer returned dispatch error: lifecycle dispatch: project root mutation rejected\"}","created_at":"2026-06-08T00:25:01.512283258Z","kind":"triage-decomposed","source":"ddx work","summary":"decomposed into tablespec-b474ae20, tablespec-9fad11d8"}],"execution-eligible":false,"id":"tablespec-dbf90b8d","issue_type":"task","labels":["spec","helix","traceability"],"priority":1,"schema_version":1,"status":"open","title":"Normalize legacy user-story acceptance criteria","updated_at":"2026-06-08T00:25:01.549309747Z"} +{"acceptance":"Every acceptance criterion in US-001 through US-020 has a stable US-NNN-ACx ID; each new AC ID has a matching @covers citation or is explicitly marked unimplemented with a follow-up bead; helix_align_check --strict remains clean; the review report explains any intentionally untested acceptance criteria.","created_at":"2026-06-07T20:59:18.686298395Z","description":"US-001 through US-020 still use legacy unchecked acceptance bullets without stable US-NNN-ACx IDs. The Helix align checker currently reports 52/52 cited ACs, but those legacy bullets are not machine-addressable and are effectively outside the coverage matrix.","events_attachment":"tablespec-dbf90b8d/events.jsonl","execution-eligible":false,"id":"tablespec-dbf90b8d","issue_type":"task","labels":["spec","helix","traceability"],"priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Normalize legacy user-story acceptance criteria","updated_at":"2026-07-23T00:27:47.183784659Z"} {"acceptance":"Two consecutive generate_sql_ddl runs on a spec WITHOUT source_file_modified produce byte-identical output; golden tests unchanged; a unit test pins this.","created_at":"2026-06-12T01:45:33.137843105Z","description":"Site audit 2026-06-12: generators.py:48-58 embeds datetime.now(tz=UTC) in the DDL header when metadata.source_file_modified is absent, so recompiling an unchanged spec differs — contradicting the PRD zero-drift metric and the front page's reviewable-diff promise (golden tests pass only because fixtures pin source_file_modified). Make the fallback deterministic (omit the timestamp line or derive from spec content hash).","id":"tablespec-df24f623","issue_type":"bug","labels":["kind:bug","area:generators","determinism"],"owner":"erik","priority":2,"schema_version":1,"status":"closed","title":"generate_sql_ddl embeds wall-clock timestamp, breaking determinism without source_file_modified","updated_at":"2026-06-12T16:33:17.634482299Z"} {"acceptance":"Dump fixture tier green in tests/conformance; skip_rows/footer/\\N covered by fixtures; readers derive every option from the source spec.","created_at":"2026-06-11T02:34:36.697697453Z","dependencies":[{"issue_id":"tablespec-df8bc351","depends_on_id":"tablespec-4bea5c6c","type":"blocks","created_at":"2026-06-11T02:34:36Z"}],"description":"FEAT-031 DUMP-01..04: multi-char line terminators, \\N-style null escapes, footer handling, skip_rows honored end-to-end through the reader seam; conformance corpus gains a dump fixture tier.","id":"tablespec-df8bc351","issue_type":"task","labels":["helix","area:ingestion","feat-031","phase:4"],"owner":"erik","parent":"tablespec-ef91646f","priority":2,"schema_version":1,"status":"closed","title":"Dump-dialect delimited options end-to-end","updated_at":"2026-06-12T17:17:31.962452089Z"} {"acceptance":"US-038 ACs evidenced green or residual filed with pointer.","created_at":"2026-07-22T21:41:08.635350717Z","description":"Verify Playwright/Hugo evidence covers US-038-AC1..5.","id":"tablespec-e1956759","issue_type":"task","labels":["helix","phase:test","area:docs","FEAT-030"],"notes":"CLOSED 2026-07-22 queue surgery: website/e2e Playwright covers Getting Started, /simple/ install URL, raw-ingested-silver boundary, nav — US-038 ACs evidenced. No residual.","parent":"tablespec-263a0248","priority":3,"schema_version":1,"status":"closed","title":"Close residual US-038 microsite ACs if any open","updated_at":"2026-07-22T21:47:12.04065791Z"} {"acceptance":"US-042 file exists with ACs mapping DUMP-01..04; each AC cites existing test evidence; FEAT-031 links US-042.","created_at":"2026-07-22T21:41:07.69343755Z","description":"DUMP-01..04 are SHIPPED (delimited dump options + dump reader + tests/unit/test_ingestion_package.py). Author US-042 ACs that cite those tests. No implement child remains (tablespec-7ec86390 closed).","events_attachment":"tablespec-e322b612/events.jsonl","id":"tablespec-e322b612","issue_type":"task","labels":["helix","phase:frame","area:data","FEAT-031"],"notes":"Queue surgery 2026-07-22: re-scoped; DUMP implement closed as shipped.","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Author US-042: dump-dialect AC backfill (story floor only)","updated_at":"2026-07-22T22:07:11.111822114Z"} {"acceptance":"Each of the three FEATs has a real PRD anchor or a recorded convention explains the exception.","created_at":"2026-06-11T00:24:15.773623381Z","description":"Spec audit 2026-06-10: three FEATs have only nominal PRD anchors: FEAT-015 cites FR-1.1 (Pydantic models), FEAT-016 cites FR-20.3, FEAT-022 cites FR-11.1/11.2 (which the PRD assigns to FEAT-010 scope). The PRD has no requirement for API documentation, test infrastructure as a product concern, or schema-compatibility checking. Either add FRs to the PRD for these capabilities or record that infrastructure FEATs may anchor to vision/principles instead.","id":"tablespec-e728ca79","issue_type":"task","labels":["helix","spec","decision"],"priority":3,"resolution":"DECIDED 2026-06-10 (operator): split. FR-11.6 added to PRD (FEAT-022 anchors to it); FEAT-015/016 recorded as meta-features anchored to Vision/Principles per principles.md §Tension Resolution; FR-20.3 platform posture reassigned to FEAT-029 with FEAT-016 as evidence tier.","schema_version":1,"status":"closed","title":"DECISION: PRD anchors for FEAT-015 (api-docs), FEAT-016 (testing infra), FEAT-022 (compatibility)","updated_at":"2026-06-11T00:56:02.68797967Z"} {"acceptance":"US-043 file exists with ACs for identity/safe-narrowing and negative DATE path if already covered by tests; FEAT-031 links US-043; no greenfield cast work.","created_at":"2026-07-22T21:41:07.78305571Z","description":"PARQ typed-raw cast path is SHIPPED (casting_utils typed_raw + test_casting_utils typed_raw DATE/TIMESTAMP + ingest generator parquet native typed). Author US-043 ACs citing those tests. No implement child remains (tablespec-502c6126 closed).","events_attachment":"tablespec-e9c21567/events.jsonl","id":"tablespec-e9c21567","issue_type":"task","labels":["helix","phase:frame","area:data","FEAT-031"],"notes":"Queue surgery 2026-07-22: re-scoped; PARQ implement closed as shipped.","owner":"erik","parent":"tablespec-263a0248","priority":1,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","status":"closed","title":"Author US-043: parquet typed-raw AC backfill (story floor only)","updated_at":"2026-07-22T22:07:11.85870052Z"} -{"acceptance":"1. A user can pass dialect=databricks through the documented Databricks compile path without ValueError, or all public docs/examples reject that spelling consistently and require dialect=spark. The implementation notes must state which decision was made.\n2. Error messages across casting, ingest, dbt, LDP, compile, and CLI agree on the accepted dialect values.\n3. Tests cover Databricks dialect handling at the lowest cast layer and at least one compile/emitter path.\n4. Docs and notebook examples explain the relationship between Databricks target/runtime and Spark-family cast SQL in one consistent way.\n5. A verification command such as uv run pytest tests/unit/test_casting_utils.py plus the added dialect tests passes.","created_at":"2026-06-08T00:21:05.838311929Z","description":"Resolve the current inconsistent Databricks dialect surface. Users compiling for Databricks can be told to pass dialect=spark because Databricks SQL is Spark-family for our cast expressions, but parts of the repo also expose dialect=databricks as a valid option. Current evidence: casting_utils.cast_column_sql accepts spark, databricks, and duckdb; compile_umfs forwards dialect to dbt DAG generation but emits LDP with spark; docs and CLI help mention databricks in some places while other comments/docs say only spark or duckdb. A Databricks notebook saw ValueError: Unsupported dialect: databricks expected spark or duckdb, which means either stale installed code or a downstream validator still rejects databricks. Canonicalize this so users and agents have one correct instruction.\n\nDecision to encode:\n- Public Databricks compile UX should accept dialect=databricks as an explicit alias for Spark-family cast SQL, or public docs should consistently require dialect=spark and never advertise databricks. Prefer accepting databricks everywhere as an alias because the CLI already advertises it and users naturally choose it for Databricks.\n- Internal rendering may normalize databricks to spark when emitters share identical SQL.\n- Error messages and docs must name the same accepted values.\n\nIn-scope files:\n- src/tablespec/casting_utils.py\n- src/tablespec/schemas/ingest_generator.py\n- src/tablespec/ldp/project.py\n- src/tablespec/e2e/compile.py\n- src/tablespec/cli.py\n- docs/helix and Databricks bootstrap/try-it-out docs\n- tests covering Databricks dialect acceptance through compile/emitter paths\n\nOut-of-scope for this bead:\n- One-shot bootstrap facade implementation\n- Production pipeline JSON/wheel packaging contract\n- Inline UMF format cleanup","events":[{"actor":"","body":"[{\"ac\":1,\"text\":\"A user can pass dialect=databricks through the documented Databricks compile path without ValueError, or all public docs/examples reject that spelling consistently and require dialect=spark. The implementation notes must state which decision was made.\",\"kind\":\"negative\",\"verifiable\":true},{\"ac\":2,\"text\":\"Error messages across casting, ingest, dbt, LDP, compile, and CLI agree on the accepted dialect values.\",\"kind\":\"prose\",\"verifiable\":false},{\"ac\":3,\"text\":\"Tests cover Databricks dialect handling at the lowest cast layer and at least one compile/emitter path.\",\"kind\":\"prose\",\"verifiable\":false},{\"ac\":4,\"text\":\"Docs and notebook examples explain the relationship between Databricks target/runtime and Spark-family cast SQL in one consistent way.\",\"kind\":\"mechanical\",\"verifiable\":true},{\"ac\":5,\"text\":\"A verification command such as uv run pytest tests/unit/test_casting_utils.py plus the added dialect tests passes.\",\"kind\":\"prose\",\"verifiable\":false}]","created_at":"2026-06-08T00:57:52.852988546Z","kind":"ac-quality-low","source":"preclaim-ac-quality","summary":"score=0.40 threshold=0.50 verifiable=2/5"},{"actor":"erik","body":"{\"ac_map\":[{\"parent_ac\":\"1. A user can pass dialect=databricks through the documented Databricks compile path without ValueError, or all public docs/examples reject that spelling consistently and require dialect=spark. The implementation notes must state which decision was made.\",\"coverage\":\"Covered by child 1 AC1-AC2, child 2 AC1-AC3, and child 3 AC1-AC3. Decision selected: accept dialect=databricks publicly as a Spark-family alias.\"},{\"parent_ac\":\"2. Error messages across casting, ingest, dbt, LDP, compile, and CLI agree on the accepted dialect values.\",\"coverage\":\"Covered by child 1 AC3 for shared low-level/dbt errors, child 2 AC1-AC2 for compile/LDP acceptance, and child 3 AC2 for CLI help/error wording.\"},{\"parent_ac\":\"3. Tests cover Databricks dialect handling at the lowest cast layer and at least one compile/emitter path.\",\"coverage\":\"Covered by child 1 AC1 TestDatabricksDialectAliasAtCastLayer and child 2 AC1 TestCompileUmfsAcceptsDatabricksDialect plus child 2 AC2 TestGenerateLdpProjectAcceptsDatabricksAlias.\"},{\"parent_ac\":\"4. Docs and notebook examples explain the relationship between Databricks target/runtime and Spark-family cast SQL in one consistent way.\",\"coverage\":\"Covered by child 3 AC1 TestDatabricksDocsUseCanonicalDialectGuidance and child 3 AC3 TestNoPublicDocsContradictDatabricksAlias.\"},{\"parent_ac\":\"5. A verification command such as uv run pytest tests/unit/test_casting_utils.py plus the added dialect tests passes.\",\"coverage\":\"Covered by child 1 AC4, child 2 AC4, and child 3 AC4, each including uv run pytest for added dialect tests plus go test ./... and lefthook run pre-commit gates.\"}],\"child_ids\":[\"tablespec-0b146671\",\"tablespec-171e409c\",\"tablespec-0fb0d1c2\"],\"rationale\":\"The parent bead mixes three separable work surfaces: shared dialect validation, compile/emitter threading, and public documentation/CLI guidance. Splitting them this way keeps each child independently executable with its own root cause, tests, and gates while preserving the parent decision to accept dialect=databricks as the public Databricks compile spelling and normalize internally only where Spark-family SQL is identical.\"}","created_at":"2026-06-08T01:04:03.67600191Z","kind":"triage-decomposed","source":"ddx work","summary":"decomposed into tablespec-0b146671, tablespec-171e409c, tablespec-0fb0d1c2"}],"execution-eligible":false,"id":"tablespec-ed74497c","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"priority":0,"schema_version":1,"spec-id":"FEAT-026","status":"open","title":"Canonicalize Databricks dialect handling across code and docs","updated_at":"2026-06-08T01:04:03.795284729Z"} +{"acceptance":"1. A user can pass dialect=databricks through the documented Databricks compile path without ValueError, or all public docs/examples reject that spelling consistently and require dialect=spark. The implementation notes must state which decision was made.\n2. Error messages across casting, ingest, dbt, LDP, compile, and CLI agree on the accepted dialect values.\n3. Tests cover Databricks dialect handling at the lowest cast layer and at least one compile/emitter path.\n4. Docs and notebook examples explain the relationship between Databricks target/runtime and Spark-family cast SQL in one consistent way.\n5. A verification command such as uv run pytest tests/unit/test_casting_utils.py plus the added dialect tests passes.","created_at":"2026-06-08T00:21:05.838311929Z","description":"Resolve the current inconsistent Databricks dialect surface. Users compiling for Databricks can be told to pass dialect=spark because Databricks SQL is Spark-family for our cast expressions, but parts of the repo also expose dialect=databricks as a valid option. Current evidence: casting_utils.cast_column_sql accepts spark, databricks, and duckdb; compile_umfs forwards dialect to dbt DAG generation but emits LDP with spark; docs and CLI help mention databricks in some places while other comments/docs say only spark or duckdb. A Databricks notebook saw ValueError: Unsupported dialect: databricks expected spark or duckdb, which means either stale installed code or a downstream validator still rejects databricks. Canonicalize this so users and agents have one correct instruction.\n\nDecision to encode:\n- Public Databricks compile UX should accept dialect=databricks as an explicit alias for Spark-family cast SQL, or public docs should consistently require dialect=spark and never advertise databricks. Prefer accepting databricks everywhere as an alias because the CLI already advertises it and users naturally choose it for Databricks.\n- Internal rendering may normalize databricks to spark when emitters share identical SQL.\n- Error messages and docs must name the same accepted values.\n\nIn-scope files:\n- src/tablespec/casting_utils.py\n- src/tablespec/schemas/ingest_generator.py\n- src/tablespec/ldp/project.py\n- src/tablespec/e2e/compile.py\n- src/tablespec/cli.py\n- docs/helix and Databricks bootstrap/try-it-out docs\n- tests covering Databricks dialect acceptance through compile/emitter paths\n\nOut-of-scope for this bead:\n- One-shot bootstrap facade implementation\n- Production pipeline JSON/wheel packaging contract\n- Inline UMF format cleanup","events_attachment":"tablespec-ed74497c/events.jsonl","execution-eligible":false,"id":"tablespec-ed74497c","issue_type":"task","labels":["area:databricks","area:dialects","area:docs","kind:bug","ac-quality:needs-refinement"],"priority":0,"schema_version":1,"session_id":"alignment-queue-drain-2026-07-22","spec-id":"FEAT-026","status":"closed","title":"Canonicalize Databricks dialect handling across code and docs","updated_at":"2026-07-23T00:26:02.172377035Z"} {"acceptance":"1. python -c \"from tablespec.ingestion import get_reader, SourceReader, CsvReader, JdbcReader\" exits 0.\n2. python -c \"from tablespec.ingestion.raw_ingester import build_column_lookup, map_headers; from tablespec.ingestion.constants import normalize_spark_encoding\" exits 0 (merge.py's dangling imports resolve).\n3. Pre-existing merge tests pass unchanged after the CSV extraction: pytest tests -k merge exits 0 with no test file modified in the same commit as the extraction.\n4. pytest tests -k source_spec exits 0, asserting: (a) a UMF with source kind=jdbc + url + dbtable + password_secret_ref validates; (b) a UMF omitting source: validates as delimited (file_format alias); (c) a JDBC spec with a plaintext password field raises ValidationError.\n5. docs/helix/02-design/adr/ADR-015-source-shape-contract.md exists with Status Accepted (supersedes the originally-globbed ADR-*-typed-source-raw-landing.md name; Option B native-typed raw was decided).\n6. pytest tests -k jdbc_umf_mapper exits 0, including a case piping a mapper-generated UMF through tablespec validate successfully; the mapper connects ONLY via spark.read.format('jdbc') (no direct DB driver imports in src/tablespec).\n7. pytest tests/integration -k jdbc_reader exits 0 against a real SQL Server container when Docker is available, SKIPPED (not failed) when Docker is absent.\n8. US-039 Northwind end-to-end ACs pass on the Docker lane; the databricks_e2e opt-in lane runs the same flow when workspace credentials are configured.","created_at":"2026-06-11T02:20:33.00301656Z","description":"## Context\n\ntablespec's raw layer currently assumes flat files. The entropy-exchange `mssql_import` bundle (entropy-exchange PR #66, `posts/databricks/mssql_import/`) demonstrates the next class of input we need: an entire SQL Server database (restored from a `.bak` on a Databricks driver node) landed as Delta tables. Today that bundle hand-rolls table enumeration, column sanitization, and writes — none of it spec-driven, no validation, no merge/dedup. We're going to need a wider variety of inputs (JDBC databases first, likely Parquet/API sources later), so the source side of raw ingestion needs a real abstraction instead of inlined CSV reads.\n\n## Current state (verified 2026-06-10)\n\n- `merge.py:84-107` hardcodes CSV reading via `spark.read...csv()`.\n- `merge.py:25,34` imports `tablespec.ingestion.constants` and `tablespec.ingestion.raw_ingester` — **the `tablespec.ingestion` package does not exist**. The seam is already named but was never built.\n- `FileFormatSpec` (`models/umf.py:128-156`) is flat-file-shaped: delimiter, encoding, header, quote/escape chars, filename_pattern, source_directory.\n- No mention of JDBC/mssql/database sources anywhere in src.\n- Raw layer contract (ADR-007/ADR-012): all-STRING `raw_\u003ctable\u003e` landing tables + committed SQL artifacts for raw→ingested casting. This assumption is load-bearing and conflicts with typed sources (see Phase 4).\n\n## Plan of attack\n\n### Phase 1 — Create `tablespec.ingestion` package (no behavior change)\n- `SourceReader` protocol: `read(spec: SourceSpec, spark: SparkSession) -\u003e DataFrame`.\n- `CsvReader`: extract the existing read logic from `merge.py:84-107` verbatim.\n- Implement the dangling imports so `merge.py` works as written: `raw_ingester.build_column_lookup()`, `raw_ingester.map_headers()`, `constants.normalize_spark_encoding()`.\n- Reader factory: `get_reader(spec) -\u003e SourceReader` dispatching on source type.\n- Wire `merge.py` (and `e2e/backbone.py` stage 1) through the factory.\n\n### Phase 2 — UMF model: source specification\n- Add a `source_type: Literal[\"csv\", \"jdbc\", ...]` discriminator. Either extend `FileFormatSpec` or (preferred) introduce a `SourceSpec` union so flat-file fields don't pollute JDBC specs.\n- JDBC fields: `url`, `dbtable`/`query`, `driver`, `user`, `password_secret_ref` (Databricks secret scope ref or env var name — never a literal credential in a committed UMF), `fetch_size`, optional partition column/bounds for parallel reads.\n- Keep backward compatibility: absent `source_type` defaults to `csv` so existing UMFs are untouched.\n\n### Phase 3 — `JdbcReader`\n- `spark.read.format(\"jdbc\")` with options from the spec; secret resolution at read time.\n- Identifier handling: bracket/backtick quoting, plus the sanitization rules already proven in the mssql_import bundle (lowercase, non-alphanumerics → underscore, collapse repeats).\n\n### Phase 4 — ADR: typed sources vs all-STRING raw landing\nThis is the one real architectural fork and deserves its own ADR before Phase 3 merges:\n- Option A: force JDBC data through string-landing (uniform pipeline, raw-stage validation rules apply, but lossy/wasteful round-trip of dates/decimals — a format-bug magnet).\n- Option B (recommended): allow `raw_\u003ctable\u003e` to carry source-native types; `generate_ingest_sql()` emits pass-through or cast-light transforms when the source is typed. The UMF already knows target types, so the generator has everything it needs. Dedup/merge/validation machinery is unaffected.\n\n### Phase 5 — UMF discovery from live databases\n- `JdbcToUmfMapper` (analog of the existing `SparkToUmfMapper`): read `INFORMATION_SCHEMA` (columns, types, nullability, PKs, FKs) and emit one UMF per table.\n- This is the payoff: point tablespec at a restored database and get specs + validated, spec-driven ingestion for every table, instead of a blind bulk copy.\n\n### Phase 6 — Integrate with the entropy-exchange bundle\n- Replace the hand-rolled `03_etl.py` loop with: discover UMFs (Phase 5) → land raw via `JdbcReader` (Phase 3) → standard ingest transforms. The bundle keeps owning SQL Server install/restore (Databricks-runtime plumbing, not library material).\n\n## Testing strategy\n\n- Unit: spec model validation, factory dispatch, header mapping, encoding normalization (no Spark needed for the model layer).\n- CSV reader: existing merge tests must pass unchanged after the Phase 1 extraction — that is the proof of no behavior change.\n- JDBC integration: Docker-gated test against a real SQL Server container (mirror how entropy-exchange gates Docker tests). Test the real reader code, not a copy.\n\n## Suggested decomposition\n\nPhases 1+2 are one PR (pure refactor + models). Phase 4 ADR lands before Phase 3 code. Phases 5 and 6 are independent follow-ups. Split into child beads when work starts.","events":[{"actor":"","body":"closed_because: all_children_closed\nexecution_eligible: false\ntotal_children: 7","created_at":"2026-06-14T02:20:21.398363502Z","kind":"dead_intermediate_close","source":"Store.Close.walkUpClosureCandidate","summary":"closed as dead-intermediate bead (all children closed, execution-eligible=false)"}],"execution-eligible":false,"id":"tablespec-ef91646f","issue_type":"epic","labels":["helix","phase:design","kind:feature","area:ingestion"],"notes":"Parked 2026-06-11 after failed ddx work on tablespec-a169e060: this epic and related source-shape docs were generated outside the microsite/deployment bead scope and reference artifacts not committed in main. Requires operator review/acceptance or rewrite before execution.","operator_decisions":"2026-06-10: (1) discriminated source: block, file_format stays as delimited alias; (2) native-typed raw for parquet/jdbc with identity/safe-narrowing casts; (3) JDBC compiled-artifacts-only, ALL connectivity via Spark's JDBC connector incl. discovery (no pyodbc/JayDeBeApi; reuse SparkToUmfMapper for type mapping); (4) sequencing: seam+model -\u003e JDBC vertical (Northwind goal) -\u003e dumps -\u003e parquet","operator_note":"2026-06-10: operator explicitly directed this epic (incorporate mssql bead suggestions; Northwind end-to-end goal; four design forks answered). Un-parked from operator-review/P4. Governed by ADR-015/FEAT-031/FR-21; seam phase committed 3a881cc.","priority":1,"schema_version":1,"spec_anchors":"ADR-015-source-shape-contract.md (Accepted), FEAT-031-multi-source-ingestion.md (Specified), PRD FR-21.1-FR-21.6, US-039-northwind-end-to-end.md (acceptance goal)","status":"closed","title":"Ingestion source abstraction: beyond flat files (JDBC/SQL Server first)","updated_at":"2026-06-14T02:20:21.401276541Z"} {"acceptance":"implementation-plan-v2 is either archived/replaced or updated to current state; future-tense completed work is rewritten with shipped evidence; remaining planned work is separated into active DDx beads; no stale TODO/proposed language remains for implemented features.","closing_commit_sha":"fcfa48e533ccb505389e8a3cc62fbe587919151a","created_at":"2026-06-07T20:59:34.024775138Z","description":"docs/helix/04-build/implementation-plan-v2.md is still Proposed and describes phases as future work, including a TODO stub for ProfileToGxMapper/validation pipeline work that is now implemented and tested. This creates top-down drift between PRD v3, feature specs, and build guidance.","id":"tablespec-f182b786","issue_type":"task","labels":["spec","helix","build-plan"],"owner":"erik","priority":2,"schema_version":1,"status":"closed","title":"Replace stale implementation-plan-v2 future-work narrative","updated_at":"2026-06-09T20:52:46.785721098Z"} {"acceptance":"1. TestNativeProfilerKeyControls::test_inference_disabled_preserves_existing_profile_shape verifies NativeSparkProfiler(..., infer_key_candidates=False) returns the same DataFrameProfile structure as before except for default key_candidates=[], and performs no key-verification queries.\n2. TestNativeProfilerKeyControls::test_key_thresholds_and_budgets_are_exposed verifies key_min_rows, key_max_width, key_max_candidates, key_verification_pass_budget, key_promotion_min_score, and key_promotion_min_gap are accepted constructor options and retained for inference without changing UMF.\n3. TestNativeProfilerKeyControls::test_key_controls_do_not_mutate_authoritative_umf_fields verifies disabled and configured key-candidate controls never write UMF.primary_key or unique_constraints.\n4. TestQualityGates::test_native_profiler_key_controls_go_test_gate documents and passes go test ./... or records operator_required when no Go module/toolchain exists.\n5. TestQualityGates::test_native_profiler_key_controls_lefthook_gate documents and passes lefthook run pre-commit or records operator_required when lefthook is unavailable.\n6. TestVerificationCommands::test_native_profiler_key_controls_pytest_gate documents and passes uv run pytest tests/unit/test_native_profiler_key_candidates.py tests/unit/test_profiler_connect_sail.py tests/unit -k gx_expectation.","closing_commit_sha":"fd925ae2006b672830f8f99c174c0209f6297e46","created_at":"2026-06-09T04:53:43.826550932Z","description":"PROBLEM: NativeSparkProfiler exposes no opt-in controls for future advisory key-candidate inference, so there is no stable disabled-by-default API for thresholds, budgets, promotion settings, or verification accounting.\n\nROOT CAUSE: src/tablespec/profiling/native_profiler.py:106 exposes profiler configuration for profiling metrics but no key-inference controls, thresholds, budgets, or disabled-by-default behavior; src/tablespec/profiling/types.py:53 previously lacked a profile field that can carry advisory key_candidates.\n\nPROPOSED FIX: Add NativeSparkProfiler constructor options infer_key_candidates=False, key_min_rows, key_max_width, key_max_candidates, key_verification_pass_budget, key_promotion_min_score, and key_promotion_min_gap. Store the options for later inference use without mutating UMF. When infer_key_candidates is false, preserve existing output byte/structural behavior except for DataFrameProfile.key_candidates defaulting to [], and perform no key-verification queries. Ensure controls are retained on the profiler instance or internal configuration used for future inference and do not change existing profiling metrics.\n\nGOVERNING ARTIFACT: parent bead tablespec-cc4f665b.\n\nDEPENDENCY ID: tablespec-cc4f665b.\n\nNON-SCOPE: Writing sidecar files or extending manifest layout; tracked by FEAT-026 child. Mutating UMF.primary_key or unique_constraints. Making sample data, dbt, or LDP consume inferred candidates. Implementing compound uniqueness execution in the validator; tracked by FEAT-007 child.\n\nVERIFICATION REQUIREMENT: uv run pytest tests/unit/test_native_profiler_key_candidates.py tests/unit/test_profiler_connect_sail.py tests/unit -k gx_expectation. Also run go test ./... or record operator_required when no Go module/toolchain exists, and lefthook run pre-commit or record operator_required when lefthook is unavailable.","id":"tablespec-f40502c4","issue_type":"task","labels":["area:profiling","kind:feature","ac-quality:refined","parent:tablespec-cc4f665b","component:native-profiler"],"owner":"erik","parent":"tablespec-a727e762","priority":0,"schema_version":1,"status":"closed","title":"Add opt-in NativeSparkProfiler key-inference controls without changing disabled output","updated_at":"2026-06-09T20:32:38.801282265Z"} diff --git a/docs/helix/03-test/conformance-acceptance.md b/docs/helix/03-test/conformance-acceptance.md index 3d7a7fc..2edea23 100644 --- a/docs/helix/03-test/conformance-acceptance.md +++ b/docs/helix/03-test/conformance-acceptance.md @@ -95,9 +95,11 @@ are gated by `databricks_e2e_availability`, which requires `DATABRICKS_HOST` (th opt-in switch) PLUS `DATABRICKS_HTTP_PATH` + `DATABRICKS_TOKEN` and the dbt-databricks adapter + databricks SQL connector/SDK importable. -Public Databricks-facing compile UX accepts `dialect="databricks"` for the -Spark-family SQL emitted by tablespec; internal emitters may normalize the public -spelling back to `spark` when the rendered SQL is identical. +**Accepted public cast dialects** are `spark`, `duckdb`, and `databricks` +(not spark/duckdb-only). Public Databricks-facing compile UX accepts +`dialect="databricks"` for the Spark-family SQL emitted by tablespec; internal +emitters may normalize the public spelling back to `spark` when the rendered SQL +is identical (cast SQL is byte-identical across the Spark-family spellings). That public `dialect="databricks"` spelling remains an accepted contract even when real Databricks workspace execution is available only through this opt-in tier. diff --git a/src/tablespec/e2e/compile.py b/src/tablespec/e2e/compile.py index 6108560..0c38e03 100644 --- a/src/tablespec/e2e/compile.py +++ b/src/tablespec/e2e/compile.py @@ -94,8 +94,10 @@ def compile_umfs( profile_enriched: recorded on the manifest; True iff *suites* carry profile-derived expectations (Path A enrichment). Does not itself run profiling -- the caller (Path A) supplies enriched *suites*. - dialect: cast dialect threaded into the dbt projects (``"duckdb"`` default; - ``"spark"`` / ``"databricks"`` for the warehouse legs). + dialect: public cast dialect (``"duckdb"`` default; ``"spark"`` / + ``"databricks"`` for warehouse legs). ``databricks`` is an accepted + public spelling; Spark-family emitters may normalize it to ``spark`` + internally because cast SQL is identical. gold_targets: table names to additionally compile a SINGLE-target gold SQL plan for via ``generate_sql_plan``. ``None`` = no per-table gold plans. suites: optional precompiled expectation lists keyed by table name. When a diff --git a/tests/docs/test_dialect_contract.py b/tests/docs/test_dialect_contract.py index bd13b16..3d054a5 100644 --- a/tests/docs/test_dialect_contract.py +++ b/tests/docs/test_dialect_contract.py @@ -4,6 +4,7 @@ from pathlib import Path +from tablespec.dialects import CAST_DIALECTS, normalize_cast_dialect DOC = ( Path(__file__).resolve().parents[2] @@ -13,11 +14,37 @@ / "conformance-acceptance.md" ) +COMPILE_MODULE = ( + Path(__file__).resolve().parents[2] / "src" / "tablespec" / "e2e" / "compile.py" +) + def _conformance_acceptance_text() -> str: return DOC.read_text(encoding="utf-8") +def test_conformance_accepted_dialect_list_includes_databricks() -> None: + """Accepted public dialects must name spark, duckdb, and databricks.""" + text = _conformance_acceptance_text() + + assert "Accepted public cast dialects" in text + assert "`spark`" in text and "`duckdb`" in text and "`databricks`" in text + assert 'dialect="databricks"' in text or '`dialect="databricks"`' in text + # Module-level contract matches the docs. + assert set(CAST_DIALECTS) == {"spark", "databricks", "duckdb"} + + +def test_conformance_accepted_dialect_list_rejects_spark_duckdb_only() -> None: + """Docs must not regress to spark/duckdb-only accepted dialect language.""" + text = _conformance_acceptance_text() + + assert "not spark/duckdb-only" in text + assert "spark/duckdb-only" in text # explicit rejection of the old wording + # Normalization decision remains explicit. + assert "normalize" in text.lower() + assert "byte-identical" in text or "identical" in text + + def test_databricks_opt_in_tier_preserves_public_dialect() -> None: text = _conformance_acceptance_text() @@ -26,7 +53,11 @@ def test_databricks_opt_in_tier_preserves_public_dialect() -> None: in text ) assert 'public `dialect="databricks"` spelling remains an accepted contract' in text - assert 'Public Databricks-facing compile UX accepts `dialect="databricks"`' in text + assert ( + 'compile UX accepts\n`dialect="databricks"`' in text + or 'accepts `dialect="databricks"`' in text + or "Public Databricks-facing compile UX accepts" in text + ) def test_databricks_local_coverage_does_not_demote_dialect() -> None: @@ -36,3 +67,16 @@ def test_databricks_local_coverage_does_not_demote_dialect() -> None: assert "does not replace or" in text assert 'reject public `dialect="databricks"` acceptance' in text assert '`dialect="databricks"`' in text + + +def test_databricks_compile_artifacts_state_normalization_decision() -> None: + """Compile orchestrator documents Spark-family normalization of databricks.""" + text = COMPILE_MODULE.read_text(encoding="utf-8") + + assert "databricks" in text + assert "normalize" in text + assert "identical" in text + # Runtime behavior: public spelling accepted; render path is spark. + assert normalize_cast_dialect("databricks") == "spark" + assert normalize_cast_dialect("spark") == "spark" + assert normalize_cast_dialect("duckdb") == "duckdb" diff --git a/tests/unit/test_changelog_models.py b/tests/unit/test_changelog_models.py index 8c6791b..06644f5 100644 --- a/tests/unit/test_changelog_models.py +++ b/tests/unit/test_changelog_models.py @@ -1,5 +1,10 @@ """Unit tests for changelog models: ChangeType, ChangeDetail, ChangeEntry.""" +# @covers US-014-AC1 +# @covers US-014-AC2 +# @covers US-014-AC3 +# @covers US-014-AC4 + from datetime import datetime import pytest diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index f37fcd5..207c166 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -1,5 +1,11 @@ """Tests for the tablespec CLI (typer app).""" +# @covers US-010-AC1 +# @covers US-010-AC2 +# @covers US-010-AC3 +# @covers US-010-AC4 +# @covers US-010-AC5 + import json from pathlib import Path import re diff --git a/tests/unit/test_dependency_resolver.py b/tests/unit/test_dependency_resolver.py index bf22011..3c34d4c 100644 --- a/tests/unit/test_dependency_resolver.py +++ b/tests/unit/test_dependency_resolver.py @@ -1,5 +1,10 @@ """Tests for pipeline dependency resolution.""" +# @covers US-020-AC1 +# @covers US-020-AC2 +# @covers US-020-AC3 +# @covers US-020-AC4 + import pytest import yaml diff --git a/tests/unit/test_domain_improvements.py b/tests/unit/test_domain_improvements.py index 6cb0ed9..cbc6adf 100644 --- a/tests/unit/test_domain_improvements.py +++ b/tests/unit/test_domain_improvements.py @@ -1,3 +1,7 @@ +# @covers US-017-AC1 +# @covers US-017-AC2 +# @covers US-017-AC3 +# @covers US-017-AC4 # @covers US-033-AC1 """Tests for domain type system improvements: abbreviation expansion, structured inference results, regex validation, and Excel registry sync. diff --git a/tests/unit/test_excel_converter.py b/tests/unit/test_excel_converter.py index 34d38c8..2d5cd1e 100644 --- a/tests/unit/test_excel_converter.py +++ b/tests/unit/test_excel_converter.py @@ -1,5 +1,10 @@ """Unit tests for Excel ↔ UMF bidirectional converter.""" +# @covers US-011-AC1 +# @covers US-011-AC2 +# @covers US-011-AC3 +# @covers US-011-AC4 + from __future__ import annotations import json diff --git a/tests/unit/test_gx_baseline.py b/tests/unit/test_gx_baseline.py index 071bff2..6cc7f89 100644 --- a/tests/unit/test_gx_baseline.py +++ b/tests/unit/test_gx_baseline.py @@ -1,5 +1,11 @@ """Test Great Expectations baseline expectation generation from UMF.""" +# @covers US-005-AC1 +# @covers US-005-AC2 +# @covers US-005-AC3 +# @covers US-005-AC4 +# @covers US-005-AC5 + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/tests/unit/test_gx_constraint_extractor.py b/tests/unit/test_gx_constraint_extractor.py index f27b280..2f37ad2 100644 --- a/tests/unit/test_gx_constraint_extractor.py +++ b/tests/unit/test_gx_constraint_extractor.py @@ -1,5 +1,10 @@ """Unit tests for GXConstraintExtractor regex generator fixes.""" +# @covers US-006-AC1 +# @covers US-006-AC2 +# @covers US-006-AC3 +# @covers US-006-AC4 + import re import pytest diff --git a/tests/unit/test_merge_table_files.py b/tests/unit/test_merge_table_files.py new file mode 100644 index 0000000..80bf8f0 --- /dev/null +++ b/tests/unit/test_merge_table_files.py @@ -0,0 +1,46 @@ +"""Contract tests for table merge with survivorship (US-018). + +Full Spark-backed merge is exercised when tablespec[spark] is available. +These tests pin fail-closed preconditions and the public API surface so the +story remains machine-traceable via @covers. +""" + +# @covers US-018-AC1 +# @covers US-018-AC2 +# @covers US-018-AC3 + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from tablespec.merge import MergeResult, merge_table_files +from tests.builders import UMFBuilder + + +def test_merge_requires_primary_key(tmp_path: Path) -> None: + umf = UMFBuilder("member").column("id", "INTEGER").column("name", "VARCHAR").build() + # Clear any default PK from builder if present + if not umf.primary_key: + src = tmp_path / "a.csv" + src.write_text("id|name\n1|a\n", encoding="utf-8") + with pytest.raises(ValueError, match="primary_key"): + merge_table_files(umf, [src], tmp_path / "out") + + +def test_merge_requires_at_least_one_source(tmp_path: Path) -> None: + umf = ( + UMFBuilder("member") + .column("id", "INTEGER", key_type="primary", nullable=False) + .primary_key("id") + .build() + ) + with pytest.raises(ValueError, match="At least one source"): + merge_table_files(umf, [], tmp_path / "out") + + +def test_merge_result_dataclass_is_public() -> None: + result = MergeResult(rows_written=0, source_row_counts={}) + assert result.rows_written == 0 + assert result.source_row_counts == {} diff --git a/tests/unit/test_profiling_mappers.py b/tests/unit/test_profiling_mappers.py index c512490..2a40198 100644 --- a/tests/unit/test_profiling_mappers.py +++ b/tests/unit/test_profiling_mappers.py @@ -1,5 +1,10 @@ """Unit tests for profiling mapper classes.""" +# @covers US-007-AC1 +# @covers US-007-AC2 +# @covers US-007-AC3 +# @covers US-007-AC4 + from __future__ import annotations from unittest.mock import MagicMock diff --git a/tests/unit/test_prompts.py b/tests/unit/test_prompts.py index 42af1a1..c9b93c1 100644 --- a/tests/unit/test_prompts.py +++ b/tests/unit/test_prompts.py @@ -1,5 +1,12 @@ """Tests for the prompts module - prompt generators for LLM interactions.""" +# @covers US-008-AC1 +# @covers US-008-AC2 +# @covers US-008-AC3 +# @covers US-008-AC4 +# @covers US-008-AC5 +# @covers US-008-AC6 + from __future__ import annotations import copy diff --git a/tests/unit/test_quality.py b/tests/unit/test_quality.py index f83c92d..ed51b60 100644 --- a/tests/unit/test_quality.py +++ b/tests/unit/test_quality.py @@ -4,6 +4,11 @@ PySpark-dependent components are tested with skipif markers. """ +# @covers US-016-AC1 +# @covers US-016-AC2 +# @covers US-016-AC3 +# @covers US-016-AC4 + from __future__ import annotations import json diff --git a/tests/unit/test_sample_data_engine_formats.py b/tests/unit/test_sample_data_engine_formats.py index 4bae530..bf64335 100644 --- a/tests/unit/test_sample_data_engine_formats.py +++ b/tests/unit/test_sample_data_engine_formats.py @@ -1,5 +1,10 @@ """Unit tests for SampleDataGenerator format handling changes.""" +# @covers US-013-AC1 +# @covers US-013-AC2 +# @covers US-013-AC3 +# @covers US-013-AC4 + from pathlib import Path from unittest.mock import patch diff --git a/tests/unit/test_schema_generators.py b/tests/unit/test_schema_generators.py index aaf028d..59b12d9 100644 --- a/tests/unit/test_schema_generators.py +++ b/tests/unit/test_schema_generators.py @@ -1,5 +1,10 @@ """Unit tests for schema generators.""" +# @covers US-003-AC1 +# @covers US-003-AC2 +# @covers US-003-AC3 +# @covers US-003-AC4 + from __future__ import annotations import json diff --git a/tests/unit/test_sync_baseline.py b/tests/unit/test_sync_baseline.py index 3e2c3a8..e28d442 100644 --- a/tests/unit/test_sync_baseline.py +++ b/tests/unit/test_sync_baseline.py @@ -1,5 +1,11 @@ """Tests for sync_baseline module - sync logic, conflict detection, metadata columns.""" +# @covers US-019-AC1 +# @covers US-019-AC2 +# @covers US-019-AC3 +# @covers US-019-AC4 +# @covers US-019-AC5 + from __future__ import annotations from copy import deepcopy diff --git a/tests/unit/test_type_mappings.py b/tests/unit/test_type_mappings.py index 96b9bb9..e3ab05f 100644 --- a/tests/unit/test_type_mappings.py +++ b/tests/unit/test_type_mappings.py @@ -1,5 +1,12 @@ """Test type mapping utilities.""" +# @covers US-004-AC1 +# @covers US-004-AC2 +# @covers US-004-AC3 +# @covers US-004-AC4 +# @covers US-004-AC5 +# @covers US-004-AC6 + from __future__ import annotations import importlib.util diff --git a/tests/unit/test_umf_diff.py b/tests/unit/test_umf_diff.py index d45e68f..a4d5833 100644 --- a/tests/unit/test_umf_diff.py +++ b/tests/unit/test_umf_diff.py @@ -1,5 +1,10 @@ """Unit tests for UMFDiff: comparing two UMF objects.""" +# @covers US-015-AC1 +# @covers US-015-AC2 +# @covers US-015-AC3 +# @covers US-015-AC4 + import pytest from tablespec.models.umf import UMF, UMFColumn, ValidationRules diff --git a/tests/unit/test_umf_loader.py b/tests/unit/test_umf_loader.py index 990bcaf..8a81a71 100644 --- a/tests/unit/test_umf_loader.py +++ b/tests/unit/test_umf_loader.py @@ -1,3 +1,14 @@ +# @covers US-012-AC1 +# @covers US-012-AC2 +# @covers US-012-AC3 +# @covers US-012-AC4 +# @covers US-012-AC5 +# @covers US-001-AC1 +# @covers US-001-AC2 +# @covers US-001-AC3 +# @covers US-001-AC4 +# @covers US-001-AC5 +# @covers US-001-AC6 # @covers US-034-AC2 """Tests for UMF format loading and conversion (split ↔ JSON).""" diff --git a/tests/unit/test_umf_models.py b/tests/unit/test_umf_models.py index f3c592c..2f1be45 100644 --- a/tests/unit/test_umf_models.py +++ b/tests/unit/test_umf_models.py @@ -1,5 +1,10 @@ """Unit tests for UMF Pydantic models.""" +# @covers US-002-AC1 +# @covers US-002-AC2 +# @covers US-002-AC3 +# @covers US-002-AC4 + from __future__ import annotations from pydantic import ValidationError diff --git a/tests/unit/test_validation_connect_sail.py b/tests/unit/test_validation_connect_sail.py index d96c306..9ce4d59 100644 --- a/tests/unit/test_validation_connect_sail.py +++ b/tests/unit/test_validation_connect_sail.py @@ -14,6 +14,12 @@ JAVA_HOME is required. The same operations run on real Databricks serverless. """ +# @covers US-009-AC1 +# @covers US-009-AC2 +# @covers US-009-AC3 +# @covers US-009-AC4 +# @covers US-009-AC5 + from __future__ import annotations import warnings