Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ jobs:
uv pip install --python "$ENV_DIR/bin/python" "$ARTIFACT"
(
cd "$TEMP_DIR"
"$ENV_DIR/bin/dander" --version | grep -F "dander 0.2.0"
"$ENV_DIR/bin/dander" --version | grep -F "dander 0.3.0rc1"
"$ENV_DIR/bin/dander" new "$PROJECT_DIR"
cd "$PROJECT_DIR"
"$ENV_DIR/bin/dander" validate
grep -F "ARG DANDER_VERSION=0.2.0" Dockerfile
grep -F "ARG DANDER_VERSION=0.3.0rc1" Dockerfile
"$ENV_DIR/bin/python" -c 'import dander; assert "site-packages" in dander.__file__'
)
INDEX=$((INDEX + 1))
Expand Down
36 changes: 34 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
# Changelog

Release notes for Dander are kept here and copied into the matching GitHub Release. Dander follows
semantic versioning while it is alpha: `0.1.x` contains fixes only, and the next product capability
will be `0.2.0`.
semantic versioning while it is alpha: released minor lines receive fixes only, and new product
capabilities enter through the next minor release.

## 0.3.0rc1 — 2026-08-04 (alpha)

### Added

- Add isolated, source-free deployment previews and explicit deployed-graph operations for Druff's
canonical PipelineGraph workflow.
- Add a real-instance-proven Odoo 19+ JSON-2 partner slice with declared schema, bounded paging,
inclusive watermark replay, transform tests, and metadata.
- Add a stateful NetSuite SuiteQL simulator and customer slice covering OAuth1 TBA, stable paging,
throttling, permissions, malformed responses, and replay. This remains simulator-validated and
is not represented as real-tenant NetSuite support.

### Changed

- Move Salesforce Accounts extraction to Bulk API 2.0 QueryAll with server-filtered SOQL, bounded
job polling, streamed locator pages, cleanup, and soft-delete visibility.
- Include ServiceNow in the retained daily operator soak without changing its existing connector
contract.

### Acceptance

- Merged Odoo installed source-free and completed initial ingestion, transform/test, metadata, and
replay against an ephemeral official Odoo 19 instance; raw and staging stayed at five unique
partner IDs and the lease cleared.
- Salesforce installed source-free and completed initial load, tied-boundary replay, one-record
server-filtered replay, and soft-delete capture against the disposable dev org; raw and staging
stayed at 14 unique Account IDs, the cursor advanced monotonically, and the lease cleared.
- Protected CI passed Python quality, Terraform and static security validation, distribution
installation, container scanning, and secret scanning on both accepted capability PRs.
- No `0.3.0rc1` tag, public package, retained deployment, or scheduler change occurred during
candidate preparation.

## 0.2.0 — 2026-08-04 (alpha)

Expand Down
45 changes: 23 additions & 22 deletions HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,43 @@

## Finished

- Merged Odoo JSON-2 through protected PR #53 and deleted its feature branch.
- Proved merged Odoo source-free against ephemeral official Odoo/PostgreSQL containers; replay stayed at five unique partners.
- Replaced Salesforce's synchronous full read with server-filtered Bulk API 2.0 QueryAll and streamed locator pages.
- Proved Salesforce source-free against the disposable dev org and GCP project, including replay and soft deletion.
- Removed the synthetic Odoo containers/API key and synthetic Salesforce Account after their proofs.
- Merged Salesforce Bulk API 2.0 through protected PR #54 after all five required CI jobs passed.
- Completed source-free Odoo and Salesforce live proofs, including replay, cursor, lease, transform/test, metadata, and soft-delete checks.
- Added sanitized proof results to operator-soak issue #26 without changing any retained schedule.
- Prepared `0.3.0rc1` release metadata and notes from merged `main`; `src/dander` is unchanged.
- Kept NetSuite explicitly simulator-validated rather than claiming real-tenant support.

## Try It

```bash
cp connectors/salesforce_jwt.example.yaml connectors/salesforce.yaml
# Edit the org domain, JWT subject, and secret references.
uv run dander run salesforce --dry-run --sandbox --project YOUR_PROJECT
uv run dander --version
uv build --out-dir /tmp/dander-v030rc1
uv run python scripts/check_distribution.py /tmp/dander-v030rc1/*.whl /tmp/dander-v030rc1/*.tar.gz
```

## Checks

- Ruff lint/format and strict mypy passed; all 677 tests passed on the final Salesforce code.
- Dependency audit, Terraform validation, distribution inspection, and local container checks passed.
- Odoo live runs extracted 5 then 3 boundary rows while preserving 5 unique rows and clearing the lease.
- Salesforce live runs proved 13-row initialization, tied-boundary replay, one-row filtered replay, and one-row soft-delete capture; 14 IDs remained unique.
- No retained scheduler, retained deployment, version, tag, or public package changed.
- Ruff lint/format and strict mypy passed; all 677 tests passed.
- Lock validation and the locked dependency audit passed with no known vulnerabilities.
- Terraform formatting and both repository roots validated with backends disabled.
- Wheel and sdist identity/archive checks passed; both installed outside the checkout, reported `0.3.0rc1`, and generated valid source-free projects pinned to the candidate.
- The local Linux image built and passed CLI, non-root-user, and bundled-asset checks.

## Decisions

- Salesforce uses an inclusive `SystemModstamp >= watermark` boundary so tied timestamps are replayed safely through idempotent SCD1.
- Bulk query jobs omit `ORDER BY` and `LIMIT` to preserve Salesforce's large-query behavior.
- NetSuite remains simulator-validated and is not represented as real-tenant support.
- Candidate preparation changes release metadata, assertions, notes, and handoff only; packaged runtime behavior is unchanged from merged `main`.
- Odoo is real-instance-proven; NetSuite remains simulator-validated pending one narrow tenant acceptance.
- Tagging, PyPI publication, retained deployment, and scheduler changes remain separate approval gates.

## Remaining

- Push `codex/salesforce-bulk2-scale`, open its focused PR, and merge only after protected CI passes.
- Add sanitized Odoo and Salesforce results to operator-soak issue #26 without changing schedules.
- Prepare a separate version-only `0.3.0rc1` PR from merged `main`; do not tag or publish it.
- Push `codex/v030rc1-release` and open a focused release-candidate PR.
- Let protected CI repeat Linux packaging, container, Terraform, dependency, and secret checks.
- Do not merge, tag, publish, or deploy the candidate without separate direction.
- Continue the existing 30-day operator soak on its current schedules.

## Review First

- `src/dander/ingestion/enterprise.py`
- `connectors/salesforce_jwt.example.yaml`
- `docs/salesforce.md`
- `CHANGELOG.md`
- `pyproject.toml`
- `.github/workflows/ci.yml`
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "dander-platform"
version = "0.2.0"
version = "0.3.0rc1"
description = "Opinionated, GCP-native, self-hosted data platform: ingest + transform + catalog behind one CLI."
readme = "README.md"
requires-python = ">=3.12"
Expand Down
2 changes: 1 addition & 1 deletion scripts/check_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pathlib import Path, PurePosixPath

EXPECTED_NAME = "dander-platform"
EXPECTED_VERSION = "0.2.0"
EXPECTED_VERSION = "0.3.0rc1"
WHEEL_REQUIRED = {
"dander/templates/project/.dockerignore",
"dander/templates/project/.gitignore",
Expand Down
2 changes: 1 addition & 1 deletion tests/pipeline/test_graph_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def test_preview_builds_source_free_snapshot_and_isolates_exact_plan(tmp_path: P
).preview(store, expected_revision=store.load().revision)

assert observations["source_free"] is True
assert "ARG DANDER_VERSION=0.2.0" in observations["dockerfile"]
assert "ARG DANDER_VERSION=0.3.0rc1" in observations["dockerfile"]
assert observations["graph"] == _GRAPH
assert observations["publish"] == ("proof-project", "us-central1", "candidate")
assert observations["plan_kwargs"]["apply"] is False
Expand Down
2 changes: 1 addition & 1 deletion tests/project/test_scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_scaffold_creates_complete_paused_project(tmp_path: Path) -> None:
manifest.validate_references(project)
assert manifest.pipelines["greenhouse_jobs"].paused
assert manifest.platform.safety.require_guarded_free_tier is False
assert "ARG DANDER_VERSION=0.2.0" in (project / "Dockerfile").read_text(encoding="utf-8")
assert "ARG DANDER_VERSION=0.3.0rc1" in (project / "Dockerfile").read_text(encoding="utf-8")
assert 'CMD ["run", "greenhouse_jobs"]' in (project / "Dockerfile").read_text(encoding="utf-8")
assert "--guarded-free-tier" not in (project / "Dockerfile").read_text(encoding="utf-8")
for relative in (
Expand Down
2 changes: 1 addition & 1 deletion tests/test_distribution_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_distribution_identity_and_version_are_public_release() -> None:
project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]

assert project["name"] == "dander-platform"
assert project["version"] == "0.2.0"
assert project["version"] == "0.3.0rc1"
assert project["scripts"]["dander"] == "dander.cli.main:app"


Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading