Skip to content

feat: Use Partial Prefix to Prompt Time Series Generation - #708

Open
seayang-nv wants to merge 6 commits into
mainfrom
seayang/partial-record-prefix-default
Open

feat: Use Partial Prefix to Prompt Time Series Generation#708
seayang-nv wants to merge 6 commits into
mainfrom
seayang/partial-record-prefix-default

Conversation

@seayang-nv

@seayang-nv seayang-nv commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Start time-series generation with a training-compatible partial record seeded by group and timestamp.
  • Use exact generated records for rolling prompt context.
  • Reject identity-only datasets during preprocessing/preflight and strengthen related regression tests.

Notes:

  • Old saved artifacts won't be able to generate anymore
  • added preflight validation that time-series datasets must contain at least one value column beyond group/timestamp.

Impact:

  • With this feature, generated time series data will be a complete copy of the original data, instead of losing the first three records.
  • This feature has negligible effect on quality and fidelity of the synthetic data. More details in Research log

First Round Review feedback addressed

  • Clarified terminology:
    • prefix: incomplete initial JSON record.
    • history: accepted generated records used in later prompts.
    • RecordPromptState: manages prefix/history state.
  • Removed the legacy training-record prefill mechanism.
  • Added typed group metadata and restored source column ordering.
  • Centralized training/generation token-boundary assembly.
  • Replaced configuration casts with validated time-series settings.
  • Applied data actions before updating group history or determining completion.
  • Replaced the absolute generation-attempt cap with consecutive no-progress tracking that resets after timestamp advancement.
  • Ensured threshold-crossing batches are retained instead of silently discarded.
  • Replaced raw group identifiers in logs and errors with stable group ordinals.
  • Moved retry counts, thresholds, and progress metrics into structured logging fields.
  • Added regression coverage for post-processing rejection, retry accounting, and identifier redaction.

Pre-Review Checklist

Ensure that the following pass:

  • mise run format && mise run check or via prek validation.
  • mise run test passes locally
  • mise run test:e2e passes locally
  • mise run test:ci-container passes locally (recommended)
  • GPU CI status check passes -- comment /sync on this PR to trigger a run (auto-triggers on ready-for-review)

Pre-Merge Checklist

  • New or updated tests for any fix or new behavior
  • Updated documentation for new features and behaviors, including docstrings for API docs.

Other Notes

  • Closes #

Summary by CodeRabbit

  • New Features
    • Improved time-series generation with partial-record prompts, rolling context, per-group retries, and context-length handling.
    • Preserved group and timestamp identity fields and source-column order during preprocessing and generation.
    • Retained time-series group metadata across training and generation.
  • Bug Fixes
    • Added clear validation errors for missing value columns or identical identity columns.
    • Improved schema ordering, prefixes, timestamps, and generated-record handling.
  • Documentation
    • Updated time-series preprocessing, generation, schema, and prompt guidance.
  • Tests
    • Expanded validation, prompting, generation, preprocessing, metadata, and GPU coverage.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Time-series preprocessing now orders identity columns first and rejects invalid identity-only inputs. Metadata stores typed group registries and source-column order. Prompt construction uses partial records and rolling history. Generation uses per-group state, context clamping, and retries.

Changes

Data contracts, metadata, and validation

Layer / File(s) Summary
Data ordering, metadata, and validation
src/nemo_safe_synthesizer/data_processing/timeseries_validation.py, src/nemo_safe_synthesizer/training/timeseries_preprocessing.py, src/nemo_safe_synthesizer/llm/metadata.py, src/nemo_safe_synthesizer/training/huggingface_backend.py, src/nemo_safe_synthesizer/preflight/checks/dataframe.py, tests/data_processing/*, tests/training/*, tests/preflight/*, tests/llm/*
Preprocessing places group and timestamp columns first. Validation rejects identical identity columns and inputs without value columns. Training metadata stores typed group values and source-column order.

Training-compatible prompt construction

Layer / File(s) Summary
Prompt helpers and token assembly
src/nemo_safe_synthesizer/data_processing/prompt_tokens.py, src/nemo_safe_synthesizer/generation/timeseries_prompting.py, src/nemo_safe_synthesizer/data_processing/assembler.py, tests/data_processing/test_prompt_tokens.py, tests/generation/test_timeseries_prompting.py, tests/data_processing/test_assembler.py
Shared utilities control BOS and EOS handling. Time-series helpers validate schemas, coerce values, build partial prefixes, preserve accepted record text, and encode separate training-compatible context segments.

Generation runtime

Layer / File(s) Summary
Partial-prefix and rolling generation
src/nemo_safe_synthesizer/generation/timeseries_backend.py, tests/generation/test_timeseries_backend.py, tests/smoke/test_nss_timeseries_gpu.py
TimeseriesBackend tracks typed groups with RecordPromptState. It builds prompts from partial prefixes and recent records, clamps output to remaining context, handles equal timestamps, and applies per-group retry state in sequential and parallel generation.

Documentation alignment

Layer / File(s) Summary
Time-series generation documentation
docs/developer-guide/example-generation.md, src/nemo_safe_synthesizer/TIMESERIES_README.md, docs/user-guide/configuration.md
Documentation describes group registries, identity-column ordering, partial-record generation, rolling history, context limits, per-group stopping behavior, retraining requirements, and configuration formatting.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🟡 Moderate · up to 98d49

This change improves time-series generation but currently exposes raw group identifiers in warning logs and understates the need to retrain older artifacts, which can create privacy concerns and failed generation attempts for users. These bounded issues should be addressed before merge.

Suggested labels: feature, bug

Suggested reviewers: binaryaaron, mckornfield, nina-xu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: using partial prefixes to prompt time-series generation.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch seayang/partial-record-prefix-default

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the feature New feature or request label Aug 7, 2026
@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR replaces training-record prefills with typed group registries and training-compatible partial-record prompts, while preserving exact accepted records as rolling history.

  • Reorders time-series identity columns and persists source-column metadata.
  • Adds value-column validation in preprocessing and preflight.
  • Introduces token-level prompt construction and per-group generation retry state.
  • The rolling-context budget remains shared across heterogeneous group prompts, so the prior generation failure is not fully resolved.

Confidence Score: 4/5

The PR is not yet safe to merge because one near-limit rolling prompt can still starve shorter groups or abort their shared generation run.

Current code computes one completion limit from the longest active prompt and applies it to every group, leaving the previously reported heterogeneous-prompt generation failure outstanding.

Files Needing Attention: src/nemo_safe_synthesizer/generation/timeseries_backend.py

Important Files Changed

Filename Overview
src/nemo_safe_synthesizer/generation/timeseries_backend.py Implements partial-prefix and rolling-history generation, but retains a shared longest-prompt completion budget that can starve or abort other groups.
src/nemo_safe_synthesizer/generation/timeseries_prompting.py Adds schema-aware partial-record serialization and token-level prompt assembly matching training boundaries.
src/nemo_safe_synthesizer/data_processing/assembler.py Replaces saved training prefills with a typed time-series group registry and shared token-boundary helpers.
src/nemo_safe_synthesizer/training/timeseries_preprocessing.py Orders identity columns for partial-prefix compatibility and preserves the original source-column order.
src/nemo_safe_synthesizer/data_processing/timeseries_validation.py Rejects overlapping identity columns and time-series datasets without generated value columns.
src/nemo_safe_synthesizer/llm/metadata.py Replaces initial-prefill metadata with typed group values and source-column ordering metadata.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Active time-series groups] --> B[Build each prefix or rolling-history prompt]
  B --> C[Measure all prompt lengths]
  C --> D[Select longest prompt]
  D --> E[Compute one shared max_tokens]
  E --> F[Single batched vLLM generation call]
  F --> G[Parse and validate each group's completion]
  G --> H[Update independent group histories and retries]
Loading

Reviews (6): Last reviewed commit: "fix: address time-series prefix review f..." | Re-trigger Greptile

Comment thread src/nemo_safe_synthesizer/generation/timeseries_backend.py
Sean Yang and others added 2 commits August 7, 2026 17:20
Signed-off-by: seayang <seayang@nvidia.com>
Signed-off-by: seayang <seayang@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bc9d6f79-fd72-4ed0-8247-b029cc6dbfe3

📥 Commits

Reviewing files that changed from the base of the PR and between 5e10d76 and 1100a3b.

📒 Files selected for processing (16)
  • docs/developer-guide/example-generation.md
  • docs/tutorials/time-series-financial-transactions.ipynb
  • docs/user-guide/configuration.md
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/data_processing/test_assembler.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_backend.py
  • tests/generation/test_timeseries_prompting.py
  • tests/preflight/test_preflight.py
  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/training/test_timeseries_preprocessing.py
💤 Files with no reviewable changes (1)
  • docs/user-guide/configuration.md
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.14)
  • GitHub Check: Smoke Tests
  • GitHub Check: End-user Wheel Install
  • GitHub Check: conventional-commit / semantic-pull-request
  • GitHub Check: Analyze (Python)
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use uv for Python dependency management and execution; never use pip or raw python. Target Python 3.11–3.14 and use modern syntax such as X | Y, list[str], and Self.
Run project tooling through mise tasks or wrapper scripts in tools/; do not invoke ruff or ty directly. Use uv run for Python execution.
Put durable implementation guidance in public function and class docstrings; put local invariants in source comments.
Use Python 3.11–3.14-compatible modern type syntax, including X | Y, list[str], and Self.

**/*.py: Use American English spelling in Python code, comments, and documentation; use from __future__ import annotations in every module.
Use BaseSettings for environment/CLI settings; prefer AliasChoices for fields accepting both Python and environment-variable names.
Pydantic model fields must include Field(description=...); prefer assignment-style Field() and use Annotated only for additional metadata or constraints.
Use @dataclass(frozen=True) for immutable value objects and validators, and field(default_factory=...) for mutable defaults; never use mutable default values directly.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal-only constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Do not use print() for operational library output; use the approved logger, click.echo() for CLI output, or sys.stdout.write() for raw tool output.
Use logger extra={} for metrics, counts, durations, and other data intended for machine querying; use f-strings for human-readable context.
Raise known errors through the Safe Synthesizer custom hierarchy, using dual inheritance where callers should also catch a built-in exception.
Use X | Y, built-in generic types, Self for fluent returns, collection ABCs for arguments, Protocol for structural boundaries, and avoid Any.
Pre...

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit pytest marker instead of the deprecated unit_test marker; async tests do not need @pytest.mark.asyncio because asyncio_mode = auto.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Read AGENTS.local.md if it exists and give its instructions top priority.
When a task matches a repository-specific skill, read the corresponding skill under .agents/skills/ instead of duplicating its workflow instructions.
Do not commit unless the user explicitly asks for a commit or PR work.
When committing, require DCO sign-off and GPG signing using git commit --signoff --gpg-sign (or -s -S); never manually add Signed-off-by or use --no-gpg-sign.
Use feature branches based on main; branch names commonly include an issue-number prefix such as <author>/123-short-name.
For recurring testing, building, syncing, bootstrapping, worktree, and GitHub workflows, use the matching skill under .agents/skills/.
For a full GPU/development environment, use uv sync --frozen --extra cu129 --extra engine --group dev; bare uv sync --frozen is incomplete and can cause ty, import-check, and GPU-test failures.

End files with a newline, contain no trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • docs/tutorials/time-series-financial-transactions.ipynb
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • docs/tutorials/time-series-financial-transactions.ipynb
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{md,py,sh,toml,yml,yaml,Dockerfile}

📄 CodeRabbit inference engine (AGENTS.md)

Follow the detailed language and file-format conventions defined in STYLE_GUIDE.md.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
tests/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

tests/**/*.py: Use absolute imports in tests.
Name test files test_*.py, classes Test*, and functions test_<module>_<expected_behavior>; prefix fixtures with fixture_ and give each fixture a one-line purpose docstring.
Use function-scoped fixtures by default, bare assert, pytest.raises(match=...), pytest.approx(), and pytest.mark.parametrize for input combinations.
Use tmp_path for file operations, mock only external boundaries, avoid shared mutable state and order dependencies, and mark CUDA-dependent tests appropriately.

All existing tests must pass before submitting a pull request; new features must include tests and bug fixes must include regression tests.

tests/**/*.py: Every test must have exactly one category marker: unit, smoke, or e2e; use modifier markers such as slow and requires_gpu only in addition to a category marker.
Use pytest.importorskip for optional dependencies that require specific extras, such as sentence_transformers and vllm.
Use fixture_mock_processor or fixture_mock_processor_without_valid_records for ParsedResponse test data, with valid_records, invalid_records, errors, and integer prompt_number fields.
Use the shared load_test_dataset(filename) and load_test_dataframe(filename) helpers for loading test datasets where applicable.
Tests should mirror the source structure, such as tests/training/, tests/generation/, and corresponding source modules.
print() is permitted in tests for debug output; Ruff rule T201 is suppressed for the tests/ directory.
Do not import helpers directly from another file under tests/; for shared methods, use a relative import from conftest.py (pytest fixtures are available automatically).
When adding a vLLM GPU smoke-test file, add pytest.mark.vllm, create a dedicated test:smoke:gpu:* mise task for per-file process isolation, and include that task in test:smoke:gpu.
GPU tests must use the requires_gpu marker; vLLM tests additionally r...

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Include the required SPDX copyright and Apache-2.0 license headers, using comment syntax appropriate to the file format.

Include SPDX copyright headers in all source files, except files explicitly listed in .copyrightignore.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Keep shared Python package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use the repository's pinned Ruff tasks for Python formatting, import sorting, and linting rather than invoking unpinned tools directly.
Run the repository's pinned ty type checker and maintain type-correct Python code.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{py,sh,yaml,yml,toml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use mise tasks with the repository's pinned tool versions for formatting, checking, and testing before submitting changes.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/preflight/test_preflight.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
tests/smoke/**/*.py

📄 CodeRabbit inference engine (tests/TESTING.md)

Mark smoke tests with the smoke pytest marker.

Files:

  • tests/smoke/test_nss_timeseries_gpu.py
src/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

src/**/*.py: Keep shared package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use TYPE_CHECKING guards for heavy imports such as pandas, torch, and transformers; use relative imports in src/.
Do not add __init__.py to test directories; every directory under src/ containing Python files must have one.
Comments should explain why rather than narrate what; do not add redundant docstrings, defensive except Exception around trusted internal calls, unjustified type ignores, or casts/Any to hide type errors.
Use pathlib.Path instead of os.path, and use explicit if/raise validation instead of assert in library code.

Files:

  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py

⚙️ CodeRabbit configuration file

Review library code against STYLE_GUIDE.md. Focus on behavior, API contracts, error handling, resource cleanup, typing, logging, and user-facing failures. Public APIs and nontrivial functions need Google-style docstrings.

Files:

  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{md,markdown}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown}: Bold is acceptable only in markdown tables where it's the conventional way to mark header-like cells in the body
Use ## headers to segment markdown sections instead of bold text
Use -- (em-dash) instead of - (hyphen) for asides in markdown

Files:

  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
docs/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/writing-docs.mdc)

docs/**/*.md: Use MkDocs Material admonition syntax (!!! note, !!! warning, ??? tip) for highlighting important information and collapsible sections in documentation
Use MkDocs Material tabs syntax (=== "Label") to present alternative views or language-specific examples in documentation
Use code block syntax with title and highlight line parameters (title="filename", hl_lines="2 3") for code examples in documentation
Use Mermaid diagram syntax (```mermaid flowchart, etc.) for visualizations in documentation

Classify documentation using Diataxis and use MkDocs Material syntax for admonitions, tabs, titled code blocks, and highlights.

docs/**/*.md: Place documentation pages under the appropriate Diataxis directory (getting-started, user-guide, architecture, reference, or dev-notes) and add new pages to the nav section of mkdocs.yml.
Write Google-style docstrings in src/nemo_safe_synthesizer/ for API reference content; generated reference pages must not be edited manually.

Files:

  • docs/developer-guide/example-generation.md
**/*.md

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Do not use decorative bold text in body content; use single backticks for inline code and -- for asides. In Python docstrings, use double backticks and MkDocs autorefs rather than Sphinx roles.

Files:

  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
docs/**

⚙️ CodeRabbit configuration file

Review documentation as MkDocs Material content. Check Diataxis fit, accurate commands, internal links, code fences, and markdown style from STYLE_GUIDE.md.

Files:

  • docs/developer-guide/example-generation.md
  • docs/tutorials/time-series-financial-transactions.ipynb
src/nemo_safe_synthesizer/training/**/*.py

⚙️ CodeRabbit configuration file

Review training changes for dataset preprocessing, model path handling, artifact writes, LoRA/DP behavior, GPU memory usage, reproducibility, and cleanup on failure.

Files:

  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
src/nemo_safe_synthesizer/data_processing/**/*.py

⚙️ CodeRabbit configuration file

Review for data-contract regressions. Check input/training/test/synthetic naming, group boundaries, token-budget math, record ordering, schema and column validation, nullable dtypes, and deterministic behavior.

Files:

  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
src/nemo_safe_synthesizer/generation/**/*.py

⚙️ CodeRabbit configuration file

Review generation changes for retry loops, stopping conditions, invalid record handling, regex/structured output contracts, backend teardown, memory cleanup, and vLLM assumptions.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
🧠 Learnings (6)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-07-27T22:07:22.590Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 673
File: tests/pii_replacer/test_edit.py:327-327
Timestamp: 2026-07-27T22:07:22.590Z
Learning: When tests read structured logging context from Python `logging.LogRecord` instances, don’t access `record.ctx` directly (it isn’t declared on `LogRecord` and will break static typing). Instead, use `getattr(record, "ctx", default)` (or an appropriate fallback) to safely handle cases where `ctx` may or may not be attached. This applies even if Ruff rule `B009` isn’t enabled in the repo.

Applied to files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-07-29T17:12:32.642Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 654
File: tests/config/test_parameters.py:116-118
Timestamp: 2026-07-29T17:12:32.642Z
Learning: In Pydantic validation tests (e.g., models configured with `from_attributes`), when asserting failures from `model_validate(...)`, assert the structured error details (such as `ValidationError.errors()[0]["type"]`, e.g. `"model_attributes_type"`) rather than relying on the human-readable error message text. This keeps tests stable even if wording changes, while still verifying the correct validation rule is triggered.

Applied to files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-08-05T19:07:15.856Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 679
File: tests/conftest.py:89-96
Timestamp: 2026-08-05T19:07:15.856Z
Learning: In the Safe Synthesizer test suite, treat CPU and CUDA installation profiles as the supported pytest collection profiles because they install PyTorch. A bare installation without PyTorch is an incomplete, unsupported profile. GPU-marked test modules may import PyTorch before tests/conftest.py::pytest_collection_modifyitems executes, so do not require that collection hook to prevent such imports.

Applied to files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_prompting.py
  • tests/data_processing/test_assembler.py
  • tests/preflight/test_preflight.py
  • tests/training/test_timeseries_preprocessing.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-06-04T16:14:09.868Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 526
File: tests/generation/test_vllm_backend.py:399-509
Timestamp: 2026-06-04T16:14:09.868Z
Learning: In this repo, only apply `pytest.mark.vllm` to smoke tests under `tests/smoke/` that actually run real vLLM GPU generation and therefore require per-file process isolation (e.g., `test-smoke-gpu-*` Makefile targets). Do not apply `pytest.mark.vllm` to unit-style tests under `tests/generation/` that merely import `vllm_backend` but never instantiate a real vLLM engine and never call `.generate()` (GPU not required). Note that `tests/conftest.py` auto-marks these as `unit` via `pytest_collection_modifyitems`, and `vllm` is not among the auto-mark categories—so if a test in `tests/generation/` has `vllm`, it should be treated as a review issue unless it meets the real GPU generation criteria above.

Applied to files:

  • tests/smoke/test_nss_timeseries_gpu.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-08-06T15:42:45.969Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 703
File: src/nemo_safe_synthesizer/pii_replacer/data_editor/detect.py:356-362
Timestamp: 2026-08-06T15:42:45.969Z
Learning: In NeMo Safe Synthesizer Python code, do not flag diagnostics solely because they report raw DataFrame column names. This is an established convention used in preflight warnings and validation errors. Flag such reporting only when an explicit repository-wide logging or privacy policy requires redaction, or when the diagnostic includes cell values, records, or other sensitive data.

Applied to files:

  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
🪛 markdownlint-cli2 (0.23.2)
src/nemo_safe_synthesizer/TIMESERIES_README.md

[warning] 266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.16.1)
tests/generation/test_timeseries_prompting.py

[error] 116-116: Possible hardcoded password assigned to argument: "bos_token"

(S106)


[error] 118-118: Possible hardcoded password assigned to argument: "eos_token"

(S106)


[error] 157-157: Possible hardcoded password assigned to argument: "bos_token"

(S106)


[error] 159-159: Possible hardcoded password assigned to argument: "eos_token"

(S106)

docs/tutorials/time-series-financial-transactions.ipynb

[warning] 146-146: Found useless expression. Either assign it to a variable or remove it.

(B018)

🔇 Additional comments (7)
src/nemo_safe_synthesizer/data_processing/timeseries_validation.py (1)

474-480: LGTM!

src/nemo_safe_synthesizer/preflight/checks/dataframe.py (1)

196-196: LGTM!

src/nemo_safe_synthesizer/training/timeseries_preprocessing.py (1)

17-41: LGTM!

Also applies to: 61-61, 111-115

tests/data_processing/test_timeseries_validation.py (1)

131-151: LGTM!

tests/preflight/test_preflight.py (1)

853-865: LGTM!

tests/training/test_timeseries_preprocessing.py (1)

37-37: LGTM!

Also applies to: 55-64, 78-78

tests/data_processing/test_assembler.py (1)

812-815: LGTM!

Comment thread docs/tutorials/time-series-financial-transactions.ipynb
Comment thread src/nemo_safe_synthesizer/data_processing/timeseries_validation.py Outdated
Comment thread src/nemo_safe_synthesizer/generation/timeseries_backend.py Outdated
Comment thread src/nemo_safe_synthesizer/generation/timeseries_prompting.py
Comment thread tests/generation/test_timeseries_prompting.py
@seayang-nv
seayang-nv force-pushed the seayang/partial-record-prefix-default branch from 1100a3b to 417ea1c Compare August 7, 2026 17:20
Comment thread src/nemo_safe_synthesizer/generation/timeseries_backend.py
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Signed-off-by: seayang <seayang@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 62147a43-6cd1-4a7c-a060-94a902519e29

📥 Commits

Reviewing files that changed from the base of the PR and between 1100a3b and c99b613.

📒 Files selected for processing (3)
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • tests/generation/test_timeseries_prompting.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: Unit Tests (3.14)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: End-user Wheel Install
  • GitHub Check: Smoke Tests
  • GitHub Check: Greptile Review
  • GitHub Check: Typecheck
  • GitHub Check: Analyze (Python)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • tests/generation/test_timeseries_prompting.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Files:

  • tests/generation/test_timeseries_prompting.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use uv for Python dependency management and execution; never use pip or raw python. Target Python 3.11–3.14 and use modern syntax such as X | Y, list[str], and Self.
Run project tooling through mise tasks or wrapper scripts in tools/; do not invoke ruff or ty directly. Use uv run for Python execution.
Put durable implementation guidance in public function and class docstrings; put local invariants in source comments.
Use Python 3.11–3.14-compatible modern type syntax, including X | Y, list[str], and Self.

**/*.py: Use American English spelling in Python code, comments, and documentation; use from __future__ import annotations in every module.
Use BaseSettings for environment/CLI settings; prefer AliasChoices for fields accepting both Python and environment-variable names.
Pydantic model fields must include Field(description=...); prefer assignment-style Field() and use Annotated only for additional metadata or constraints.
Use @dataclass(frozen=True) for immutable value objects and validators, and field(default_factory=...) for mutable defaults; never use mutable default values directly.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal-only constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Do not use print() for operational library output; use the approved logger, click.echo() for CLI output, or sys.stdout.write() for raw tool output.
Use logger extra={} for metrics, counts, durations, and other data intended for machine querying; use f-strings for human-readable context.
Raise known errors through the Safe Synthesizer custom hierarchy, using dual inheritance where callers should also catch a built-in exception.
Use X | Y, built-in generic types, Self for fluent returns, collection ABCs for arguments, Protocol for structural boundaries, and avoid Any.
Pre...

Files:

  • tests/generation/test_timeseries_prompting.py
**/tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit pytest marker instead of the deprecated unit_test marker; async tests do not need @pytest.mark.asyncio because asyncio_mode = auto.

Files:

  • tests/generation/test_timeseries_prompting.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Read AGENTS.local.md if it exists and give its instructions top priority.
When a task matches a repository-specific skill, read the corresponding skill under .agents/skills/ instead of duplicating its workflow instructions.
Do not commit unless the user explicitly asks for a commit or PR work.
When committing, require DCO sign-off and GPG signing using git commit --signoff --gpg-sign (or -s -S); never manually add Signed-off-by or use --no-gpg-sign.
Use feature branches based on main; branch names commonly include an issue-number prefix such as <author>/123-short-name.
For recurring testing, building, syncing, bootstrapping, worktree, and GitHub workflows, use the matching skill under .agents/skills/.
For a full GPU/development environment, use uv sync --frozen --extra cu129 --extra engine --group dev; bare uv sync --frozen is incomplete and can cause ty, import-check, and GPU-test failures.

End files with a newline, contain no trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

Files:

  • tests/generation/test_timeseries_prompting.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • tests/generation/test_timeseries_prompting.py
**/*.{md,py,sh,toml,yml,yaml,Dockerfile}

📄 CodeRabbit inference engine (AGENTS.md)

Follow the detailed language and file-format conventions defined in STYLE_GUIDE.md.

Files:

  • tests/generation/test_timeseries_prompting.py
tests/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

tests/**/*.py: Use absolute imports in tests.
Name test files test_*.py, classes Test*, and functions test_<module>_<expected_behavior>; prefix fixtures with fixture_ and give each fixture a one-line purpose docstring.
Use function-scoped fixtures by default, bare assert, pytest.raises(match=...), pytest.approx(), and pytest.mark.parametrize for input combinations.
Use tmp_path for file operations, mock only external boundaries, avoid shared mutable state and order dependencies, and mark CUDA-dependent tests appropriately.

All existing tests must pass before submitting a pull request; new features must include tests and bug fixes must include regression tests.

tests/**/*.py: Every test must have exactly one category marker: unit, smoke, or e2e; use slow and requires_gpu as modifiers where applicable.
Use pytest.importorskip for optional dependencies that require specific extras, such as sentence_transformers and vllm.
Use the shared fixture_mock_processor or fixture_mock_processor_without_valid_records fixtures for processor mocks, with ParsedResponse fields valid_records, invalid_records, errors, and prompt_number.
Use load_test_dataset(filename) and load_test_dataframe(filename) for loading shared test datasets.
Keep tokenizers function-scoped unless there is a specific reason to change scope; fixture_session_cache_dir is session-scoped.
Tests should mirror the source structure, such as tests/training/, tests/generation/, and related module directories.
print() is permitted in tests because Ruff rule T201 is suppressed for the tests/ directory.
Do not import directly from another ordinary file under tests/; share methods through relative imports from conftest.py when needed.
When debugging NSS logs with pytest, use -s or --capture=no; use -n0 for visible output when xdist is involved.

Files:

  • tests/generation/test_timeseries_prompting.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/generation/test_timeseries_prompting.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Include the required SPDX copyright and Apache-2.0 license headers, using comment syntax appropriate to the file format.

Include SPDX copyright headers in all source files, except files explicitly listed in .copyrightignore.

Files:

  • tests/generation/test_timeseries_prompting.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Keep shared Python package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use the repository's pinned Ruff tasks for Python formatting, import sorting, and linting rather than invoking unpinned tools directly.
Run the repository's pinned ty type checker and maintain type-correct Python code.

Files:

  • tests/generation/test_timeseries_prompting.py
**/*.{py,sh,yaml,yml,toml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use mise tasks with the repository's pinned tool versions for formatting, checking, and testing before submitting changes.

Files:

  • tests/generation/test_timeseries_prompting.py
🧠 Learnings (5)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
📚 Learning: 2026-07-27T22:07:22.590Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 673
File: tests/pii_replacer/test_edit.py:327-327
Timestamp: 2026-07-27T22:07:22.590Z
Learning: When tests read structured logging context from Python `logging.LogRecord` instances, don’t access `record.ctx` directly (it isn’t declared on `LogRecord` and will break static typing). Instead, use `getattr(record, "ctx", default)` (or an appropriate fallback) to safely handle cases where `ctx` may or may not be attached. This applies even if Ruff rule `B009` isn’t enabled in the repo.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
📚 Learning: 2026-07-29T17:12:32.642Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 654
File: tests/config/test_parameters.py:116-118
Timestamp: 2026-07-29T17:12:32.642Z
Learning: In Pydantic validation tests (e.g., models configured with `from_attributes`), when asserting failures from `model_validate(...)`, assert the structured error details (such as `ValidationError.errors()[0]["type"]`, e.g. `"model_attributes_type"`) rather than relying on the human-readable error message text. This keeps tests stable even if wording changes, while still verifying the correct validation rule is triggered.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
📚 Learning: 2026-08-05T19:07:15.856Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 679
File: tests/conftest.py:89-96
Timestamp: 2026-08-05T19:07:15.856Z
Learning: In the Safe Synthesizer test suite, treat CPU and CUDA installation profiles as the supported pytest collection profiles because they install PyTorch. A bare installation without PyTorch is an incomplete, unsupported profile. GPU-marked test modules may import PyTorch before tests/conftest.py::pytest_collection_modifyitems executes, so do not require that collection hook to prevent such imports.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
📚 Learning: 2026-06-04T16:14:09.868Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 526
File: tests/generation/test_vllm_backend.py:399-509
Timestamp: 2026-06-04T16:14:09.868Z
Learning: In this repo, only apply `pytest.mark.vllm` to smoke tests under `tests/smoke/` that actually run real vLLM GPU generation and therefore require per-file process isolation (e.g., `test-smoke-gpu-*` Makefile targets). Do not apply `pytest.mark.vllm` to unit-style tests under `tests/generation/` that merely import `vllm_backend` but never instantiate a real vLLM engine and never call `.generate()` (GPU not required). Note that `tests/conftest.py` auto-marks these as `unit` via `pytest_collection_modifyitems`, and `vllm` is not among the auto-mark categories—so if a test in `tests/generation/` has `vllm`, it should be treated as a review issue unless it meets the real GPU generation criteria above.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
🪛 Ruff (0.16.1)
tests/generation/test_timeseries_prompting.py

[error] 118-118: Possible hardcoded password assigned to argument: "bos_token"

(S106)


[error] 120-120: Possible hardcoded password assigned to argument: "eos_token"

(S106)


[error] 159-159: Possible hardcoded password assigned to argument: "bos_token"

(S106)


[error] 161-161: Possible hardcoded password assigned to argument: "eos_token"

(S106)

🔇 Additional comments (8)
tests/generation/test_timeseries_prompting.py (8)

1-18: LGTM!


20-38: LGTM!


41-58: LGTM!


61-74: LGTM!


76-89: LGTM!


91-99: LGTM!


100-141: LGTM!


145-165: LGTM!

Comment thread tests/generation/test_timeseries_prompting.py Outdated
Comment thread tests/generation/test_timeseries_prompting.py Outdated
Signed-off-by: seayang <seayang@nvidia.com>
Signed-off-by: seayang <seayang@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/nemo_safe_synthesizer/generation/timeseries_backend.py (1)

923-923: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a bounded termination rule for interval-less time series. Preflight permits timestamp_interval_seconds=None when every group has one record, so _process_group_result skips chronological validation. Valid records below _stop_timestamp_value then reset the retry counter and keep active_states non-empty indefinitely. Reject this configuration or add a maximum-attempt bound, and remove the obsolete global stop conditions from the class docstring.

Source: Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f2230332-a204-455a-9bef-0f13ae7dd18b

📥 Commits

Reviewing files that changed from the base of the PR and between 1195a18 and 8ae38b0.

📒 Files selected for processing (1)
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
📜 Review details
⏰ Context from checks skipped due to timeout. (11)
  • GitHub Check: Greptile Review
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Smoke Tests
  • GitHub Check: End-user Wheel Install
  • GitHub Check: Unit Tests (3.14)
  • GitHub Check: Typecheck
  • GitHub Check: Analyze (Python)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use uv for Python dependency management and execution; never use pip or raw python. Target Python 3.11–3.14 and use modern syntax such as X | Y, list[str], and Self.
Run project tooling through mise tasks or wrapper scripts in tools/; do not invoke ruff or ty directly. Use uv run for Python execution.
Put durable implementation guidance in public function and class docstrings; put local invariants in source comments.
Use Python 3.11–3.14-compatible modern type syntax, including X | Y, list[str], and Self.

**/*.py: Use American English spelling in Python code, comments, and documentation; use from __future__ import annotations in every module.
Use BaseSettings for environment/CLI settings; prefer AliasChoices for fields accepting both Python and environment-variable names.
Pydantic model fields must include Field(description=...); prefer assignment-style Field() and use Annotated only for additional metadata or constraints.
Use @dataclass(frozen=True) for immutable value objects and validators, and field(default_factory=...) for mutable defaults; never use mutable default values directly.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal-only constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Do not use print() for operational library output; use the approved logger, click.echo() for CLI output, or sys.stdout.write() for raw tool output.
Use logger extra={} for metrics, counts, durations, and other data intended for machine querying; use f-strings for human-readable context.
Raise known errors through the Safe Synthesizer custom hierarchy, using dual inheritance where callers should also catch a built-in exception.
Use X | Y, built-in generic types, Self for fluent returns, collection ABCs for arguments, Protocol for structural boundaries, and avoid Any.
Pre...

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Read AGENTS.local.md if it exists and give its instructions top priority.
When a task matches a repository-specific skill, read the corresponding skill under .agents/skills/ instead of duplicating its workflow instructions.
Do not commit unless the user explicitly asks for a commit or PR work.
When committing, require DCO sign-off and GPG signing using git commit --signoff --gpg-sign (or -s -S); never manually add Signed-off-by or use --no-gpg-sign.
Use feature branches based on main; branch names commonly include an issue-number prefix such as <author>/123-short-name.
For recurring testing, building, syncing, bootstrapping, worktree, and GitHub workflows, use the matching skill under .agents/skills/.
For a full GPU/development environment, use uv sync --frozen --extra cu129 --extra engine --group dev; bare uv sync --frozen is incomplete and can cause ty, import-check, and GPU-test failures.

End files with a newline, contain no trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{md,py,sh,toml,yml,yaml,Dockerfile}

📄 CodeRabbit inference engine (AGENTS.md)

Follow the detailed language and file-format conventions defined in STYLE_GUIDE.md.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
src/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

src/**/*.py: Keep shared package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use TYPE_CHECKING guards for heavy imports such as pandas, torch, and transformers; use relative imports in src/.
Do not add __init__.py to test directories; every directory under src/ containing Python files must have one.
Comments should explain why rather than narrate what; do not add redundant docstrings, defensive except Exception around trusted internal calls, unjustified type ignores, or casts/Any to hide type errors.
Use pathlib.Path instead of os.path, and use explicit if/raise validation instead of assert in library code.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py

⚙️ CodeRabbit configuration file

Review library code against STYLE_GUIDE.md. Focus on behavior, API contracts, error handling, resource cleanup, typing, logging, and user-facing failures. Public APIs and nontrivial functions need Google-style docstrings.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Include the required SPDX copyright and Apache-2.0 license headers, using comment syntax appropriate to the file format.

Include SPDX copyright headers in all source files, except files explicitly listed in .copyrightignore.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Keep shared Python package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use the repository's pinned Ruff tasks for Python formatting, import sorting, and linting rather than invoking unpinned tools directly.
Run the repository's pinned ty type checker and maintain type-correct Python code.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{py,sh,yaml,yml,toml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use mise tasks with the repository's pinned tool versions for formatting, checking, and testing before submitting changes.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
src/nemo_safe_synthesizer/generation/**/*.py

⚙️ CodeRabbit configuration file

Review generation changes for retry loops, stopping conditions, invalid record handling, regex/structured output contracts, backend teardown, memory cleanup, and vLLM assumptions.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
🧠 Learnings (1)
📚 Learning: 2026-08-06T15:42:45.969Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 703
File: src/nemo_safe_synthesizer/pii_replacer/data_editor/detect.py:356-362
Timestamp: 2026-08-06T15:42:45.969Z
Learning: In NeMo Safe Synthesizer Python code, do not flag diagnostics solely because they report raw DataFrame column names. This is an established convention used in preflight warnings and validation errors. Flag such reporting only when an explicit repository-wide logging or privacy policy requires redaction, or when the diagnostic includes cell values, records, or other sensitive data.

Applied to files:

  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
🔇 Additional comments (2)
src/nemo_safe_synthesizer/generation/timeseries_backend.py (2)

18-18: LGTM!

Also applies to: 30-37, 75-75, 95-97, 146-146, 159-159, 210-210, 223-227, 237-248, 257-300, 392-398, 442-444, 453-455, 560-563, 572-577, 617-657, 835-853, 871-872, 890-900


1007-1007: 🩺 Stability & Availability

No constructor error occurs. GenerationBatches.__init__ defaults both parameters to None. The reduced call is valid and still stops on zero-valid batches via STOP_NO_RECORDS.

			> Likely an incorrect or invalid review comment.

@@ -262,9 +262,9 @@ these conditions are met:
### Initial prefill

For each group, the first 3 training records are stored as `initial_prefill` --

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Do we still need to store the first 3 training records? Would 1 be sufficient now?

Actually, this is getting confusing now. initial_prefill as a dictionary with 3 records may be right, but GroupState.initial_prefill is the prefix only version with partial of the 1st record.

Overall, naming of these different things is getting a bit hard to follow. I thought I had the prefill = whole records, prefix = initial partial record making sense to me, but then that's not always the case as GroupState.current_prefill may contain either depending on where during generation we are.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I removed the old training-record prefill mechanism and initial_prefill metadata entirely. The terminology is now:

  • prefix: the incomplete initial JSON record
  • history: accepted generated records used by later prompts
  • RecordPromptState: the state containing the prefix/history and controlling the transition between them

The artifact now stores only typed group values, not copies of training records.

exact accepted record text is appended to the group's rolling context.
4. The three most recent accepted records become the prefill for the next
prompt.
5. This repeats until the target time range is covered or retries are

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This is a bit hard to read and follow. Please make an editing pass.

Possible things to clarify:

  • main loop of inference (using up to 3 most recently generated records) versus the first prompt, maybe explain the main loop and then have the initializaiton be a special case noted afterwards
  • initial prompt from incomplete JSON record may generate 1 or more records, it doesn't just complete the fields of 1 record
  • "constructed prefix" is confusing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. The sequential-generation documentation now explains the normal sliding-history loop first, followed by the initial prefix iteration as a special case. It also clarifies that the prefix prompt may generate one or more records and removes the ambiguous “constructed prefix” wording.

Comment thread docs/user-guide/configuration.md
last_timestamp_seconds: int | None = None
"""Timestamp (in seconds) of the most recently generated record, used for chronological validation."""

processor_prefix: str = ""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: This is a substring of initial_prefill, right? What's the benefit of storing this separately, versus calculating it from initial_prefill, or splitting on the combination of prompt and completion?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed by removing processor_prefix and the old initial_prefill state. RecordPromptState now owns the initial prefix directly and exposes it as the completion prefix only while generation is in prefix mode.

to seed generation for each group.
_group_prefills (dict[str, str]): Saved mapping of group IDs to training
sample text. The keys define generation groups; values remain
available internally but are not inserted into prompts.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Do we use the values somewhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were not used. I wanted to keep them in case we could use them for a different feature etc. I figured it's rather easy to do it if we do need it, so I removed them. Metadata now stores timeseries_group_values, an ordered list of typed group identifiers used to initialize one generation stream per training group. No training-record text is retained for prompting.

"""Return the declared JSON types for a schema column.

Prefix seed values do not always retain their training-data types: group
IDs become strings when stored as dictionary keys, and configured

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Why do we lose type information? Python dictionaries can have integer or float keys. This feels like patching over an upstream issue where we control all the upstream code, rather than fixing it at the source. Is it not feasible to get the properly runtime typed values passed to build_partial_record_prefix and avoid this machinery inspecting json schema objects?

Side note, #699 would help in giving us a nicely typed pydantic model or something to work with here instead of all the extra logic to pull info out of a json schema. But a fix for the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed at the source. The artifact now stores typed group values in timeseries_group_values, preserving strings, integers, floats, and booleans through metadata serialization. Schema inspection remains only where needed to serialize configured timestamp values consistently with the saved training schema and validate prefix field order.

A view with group and timestamp columns first, followed by all remaining
columns in their original relative order.
"""
leading_columns = list(dict.fromkeys((group_by_column, timestamp_column)))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
leading_columns = list(dict.fromkeys((group_by_column, timestamp_column)))
leading_columns = [group_by_column, timestamp_column]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? leading_columns is just a regular list[str], right, can create it directly instead of going through dict.fromkeys?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented as suggested: leading_columns = [group_by_column, timestamp_column].

training_df,
validation.group_by_column,
validation.timestamp_column,
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: This means the resulting synthetic data will have the column reordered too, right? Not a big deal, but we might consider putting the order back to match training data before returning to the user.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented. Training saves the original source-column order in timeseries_source_columns, and generation restores that order before returning the synthetic DataFrame while retaining any unexpected extra columns at the end.

serialized = records_to_jsonl([ordered_values]).rstrip("\n")
if not serialized.endswith("}"):
raise GenerationError("Could not serialize the initial time-series partial record.")
return f'{serialized[:-1]},"'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: This all feels very brittle and potentially model specific as we're making assumptions about how the tokenizer works. Don't have any better ideas right now, but something to keep in mind, and maybe helped by some of the tokenization work @binaryaaron has been looking at.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The explicit token construction is still necessary because model families differ in whether their tokenizers inject the required BOS/EOS markers during inference. To reduce the risk, the boundary logic is now shared with training rather than duplicated, and regression tests verify that both prefix and history generation IDs match the corresponding training-example IDs.

"""Partial first-record prefix used to seed generation."""

current_prefill: str
"""Current prefill string, updated as generation progresses to include recently generated records."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Clarify this starts with the same value as initial_prefill? Do we need to keep initial_prefill as a separate member variable at all? Part of several comments about the differences between initial_prefill, current_prefill, and processor_prefix and understanding what logic applies depending on whether the group has successfully generated a record or not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been removed. RecordPromptState.prefix stores only the incomplete initial record, while RecordPromptState.history stores accepted generated records. The explicit using_prefix flag controls which one is active, so there is no duplicate initial_prefill/current_prefill state.

Signed-off-by: seayang <seayang@nvidia.com>
@coderabbitai coderabbitai Bot added the bug Defects in shipped behavior label Aug 17, 2026
Comment on lines 878 to 882
modified_params, effective_samples_per_prompt = self._build_modified_sampling_params(
sampling_params, len(active_states)
sampling_params,
len(active_states),
max_prompt_tokens=max(len(token_ids) for token_ids in prompt_token_ids),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Shared budget still starves groups

When active groups have different rolling-history lengths, this derives one completion budget from the longest prompt and applies it to every group. Shorter groups consequently receive truncated, invalid JSON completions and can exhaust their retries despite having available context; when the longest prompt fills the context window, the resulting GenerationError aborts the entire run before shorter groups generate.

Knowledge Base Used: Generation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent (review-pr): Confirmed; this remains blocking

A single SamplingParams object is capped using the longest active prompt, then applied to every prompt in the batch. Shorter prompts lose usable completion space. The base parameters are also capped using _get_prompt_token_count(), so changing only this call may retain the shared limit. Please compute a completion budget for each prompt and pass an aligned SamplingParams sequence, or otherwise batch groups by compatible budgets.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is clear. _build_modified_sampling_params is called once with max(...) over all prompt lengths, and the returned single SamplingParams is used for every prompt. vLLM's LLM.generate accepts a list[SamplingParams] aligned to the prompt list, so you can give each prompt its own budget.

The minimal change inside _generate_parallel_groups:

Suggested change
modified_params, effective_samples_per_prompt = self._build_modified_sampling_params(
sampling_params, len(active_states)
sampling_params,
len(active_states),
max_prompt_tokens=max(len(token_ids) for token_ids in prompt_token_ids),
)
# Build token prompts that reproduce the training BOS/EOS boundary.
prompt_token_ids = [
self._build_prompt_token_ids(state.prompt_state.prompt_segments) for state in active_states
]
prompts = [TokensPrompt(prompt_token_ids=token_ids) for token_ids in prompt_token_ids]
group_batches: dict[TimeSeriesGroupValue, Batch] = {
state.group_id: Batch(processor=self.processor) for state in active_states
}
# Derive shared knobs (n, temperature, …) from the longest prompt,
# then build a per-prompt SamplingParams so each group gets the full
# remaining context rather than being capped to the longest prompt's budget.
_, effective_samples_per_prompt = self._build_modified_sampling_params(
sampling_params,
len(active_states),
max_prompt_tokens=max(len(t) for t in prompt_token_ids),
)
per_prompt_params = [
self._build_modified_sampling_params(
sampling_params,
len(active_states),
max_prompt_tokens=len(token_ids),
)[0]
for token_ids in prompt_token_ids
]

Then pass per_prompt_params instead of modified_params to llm.generate:

outputs = self.llm.generate(
    prompts=prompts,
    sampling_params=per_prompt_params,   # list aligned to prompts
    lora_request=self.lora_req,
)

One remaining caveat: _get_prompt_token_count() (used in generate() to size the base SamplingParams) still returns the longest initial prefix length. That base object is now only used to seed sampling_params before it reaches _build_modified_sampling_params, so the per-prompt clamp in _build_modified_sampling_params will always win — but it's worth a comment there so the two-level capping is obvious to future readers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remained unaddressed for now..

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/developer-guide/example-generation.md (1)

469-473: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Document the full artifact migration requirement.

Lines 469-473 state that only artifacts with a different saved schema order require retraining. The PR objective states that previously saved time-series artifacts no longer support generation because the new generation path requires the group registry and prompt metadata. Users with older artifacts whose column order matches can follow this page and still encounter a generation failure. State that all artifacts created before this change require retraining, or document the exact metadata or version condition that remains compatible.

Proposed documentation update
-Older artifacts whose saved schema uses another order
-must be retrained; generation fails explicitly instead of silently changing
-prompting behavior.
+Previously saved time-series artifacts must be retrained. They do not contain
+the registry and prompt metadata required by the current generation path, so
+generation fails explicitly instead of silently changing prompting behavior.

As per path instructions: prioritize documentation issues that can break user workflows and verify documented behavior against the supplied contract.

Source: Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 697dfeee-8027-4a87-8d9d-de303e58f93b

📥 Commits

Reviewing files that changed from the base of the PR and between 8ae38b0 and 98d49c5.

📒 Files selected for processing (19)
  • docs/developer-guide/example-generation.md
  • src/nemo_safe_synthesizer/TIMESERIES_README.md
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • tests/data_processing/test_assembler.py
  • tests/data_processing/test_prompt_tokens.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/generation/test_timeseries_backend.py
  • tests/generation/test_timeseries_prompting.py
  • tests/llm/test_metadata.py
  • tests/smoke/test_nss_timeseries_gpu.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/nemo_safe_synthesizer/training/timeseries_preprocessing.py
  • src/nemo_safe_synthesizer/preflight/checks/dataframe.py
  • tests/smoke/test_nss_timeseries_gpu.py
  • src/nemo_safe_synthesizer/TIMESERIES_README.md

Included review availability: Your plan includes up to 12 reviews per rolling hour; 11 remain after this review.

📜 Review details
⏰ Context from checks skipped due to timeout. (7)
  • GitHub Check: Greptile Review
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.14)
  • GitHub Check: End-user Wheel Install
  • GitHub Check: Smoke Tests
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • docs/developer-guide/example-generation.md
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use uv for Python dependency management and execution; never use pip or raw python. Target Python 3.11–3.14 and use modern syntax such as X | Y, list[str], and Self.
Run project tooling through mise tasks or wrapper scripts in tools/; do not invoke ruff or ty directly. Use uv run for Python execution.
Put durable implementation guidance in public function and class docstrings; put local invariants in source comments.
Use Python 3.11–3.14-compatible modern type syntax, including X | Y, list[str], and Self.

**/*.py: Use American English spelling in Python code, comments, and documentation; use from __future__ import annotations in every module.
Use BaseSettings for environment/CLI settings; prefer AliasChoices for fields accepting both Python and environment-variable names.
Pydantic model fields must include Field(description=...); prefer assignment-style Field() and use Annotated only for additional metadata or constraints.
Use @dataclass(frozen=True) for immutable value objects and validators, and field(default_factory=...) for mutable defaults; never use mutable default values directly.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal-only constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Do not use print() for operational library output; use the approved logger, click.echo() for CLI output, or sys.stdout.write() for raw tool output.
Use logger extra={} for metrics, counts, durations, and other data intended for machine querying; use f-strings for human-readable context.
Raise known errors through the Safe Synthesizer custom hierarchy, using dual inheritance where callers should also catch a built-in exception.
Use X | Y, built-in generic types, Self for fluent returns, collection ABCs for arguments, Protocol for structural boundaries, and avoid Any.
Pre...

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit pytest marker instead of the deprecated unit_test marker; async tests do not need @pytest.mark.asyncio because asyncio_mode = auto.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Read AGENTS.local.md if it exists and give its instructions top priority.
When a task matches a repository-specific skill, read the corresponding skill under .agents/skills/ instead of duplicating its workflow instructions.
Do not commit unless the user explicitly asks for a commit or PR work.
When committing, require DCO sign-off and GPG signing using git commit --signoff --gpg-sign (or -s -S); never manually add Signed-off-by or use --no-gpg-sign.
Use feature branches based on main; branch names commonly include an issue-number prefix such as <author>/123-short-name.
For recurring testing, building, syncing, bootstrapping, worktree, and GitHub workflows, use the matching skill under .agents/skills/.
For a full GPU/development environment, use uv sync --frozen --extra cu129 --extra engine --group dev; bare uv sync --frozen is incomplete and can cause ty, import-check, and GPU-test failures.

End files with a newline, contain no trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

All contributions must be signed off to certify that you have the right to submit the code.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • docs/developer-guide/example-generation.md

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • docs/developer-guide/example-generation.md
**/*.{md,py,sh,toml,yml,yaml,Dockerfile}

📄 CodeRabbit inference engine (AGENTS.md)

Follow the detailed language and file-format conventions defined in STYLE_GUIDE.md.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • docs/developer-guide/example-generation.md
tests/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

tests/**/*.py: Use absolute imports in tests.
Name test files test_*.py, classes Test*, and functions test_<module>_<expected_behavior>; prefix fixtures with fixture_ and give each fixture a one-line purpose docstring.
Use function-scoped fixtures by default, bare assert, pytest.raises(match=...), pytest.approx(), and pytest.mark.parametrize for input combinations.
Use tmp_path for file operations, mock only external boundaries, avoid shared mutable state and order dependencies, and mark CUDA-dependent tests appropriately.

tests/**/*.py: Every test must have exactly one category marker: unit, smoke, or e2e; use slow and requires_gpu as modifiers where applicable.
Use pytest.importorskip for optional dependencies that require specific extras, such as sentence_transformers and vllm.
Use the shared fixture_mock_processor or fixture_mock_processor_without_valid_records fixtures for processor mocks, with ParsedResponse fields valid_records, invalid_records, errors, and prompt_number.
Use load_test_dataset(filename) and load_test_dataframe(filename) for loading shared test datasets.
Keep tokenizers function-scoped unless there is a specific reason to change scope; fixture_session_cache_dir is session-scoped.
Tests should mirror the source structure, such as tests/training/, tests/generation/, and related module directories.
print() is permitted in tests because Ruff rule T201 is suppressed for the tests/ directory.
Do not import directly from another ordinary file under tests/; share methods through relative imports from conftest.py when needed.
When debugging NSS logs with pytest, use -s or --capture=no; use -n0 for visible output when xdist is involved.

tests/**/*.py: New features include tests
Bug fixes include regression tests

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Include the required SPDX copyright and Apache-2.0 license headers, using comment syntax appropriate to the file format.

All source files (.py, .sh, .yaml, .yml, .md) require SPDX copyright headers.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
  • docs/developer-guide/example-generation.md
**/*.{py,pyi}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,pyi}: Although the default development/runtime interpreter is Python 3.13, source code must remain Python 3.11 syntax-compatible until the NMP platform moves its base Python version to 3.12.
Do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic class/function parameters in shared package code yet.

Files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • tests/data_processing/test_timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • tests/generation/test_timeseries_backend.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
src/**/*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

src/**/*.py: Keep shared package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Use TYPE_CHECKING guards for heavy imports such as pandas, torch, and transformers; use relative imports in src/.
Do not add __init__.py to test directories; every directory under src/ containing Python files must have one.
Comments should explain why rather than narrate what; do not add redundant docstrings, defensive except Exception around trusted internal calls, unjustified type ignores, or casts/Any to hide type errors.
Use pathlib.Path instead of os.path, and use explicit if/raise validation instead of assert in library code.

just write Google-style docstrings in src/nemo_safe_synthesizer/ and they will appear on the next build.

Files:

  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py

⚙️ CodeRabbit configuration file

Review library code against STYLE_GUIDE.md. Focus on behavior, API contracts, error handling, resource cleanup, typing, logging, and user-facing failures. Public APIs and nontrivial functions need Google-style docstrings.

Files:

  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
src/nemo_safe_synthesizer/training/**/*.py

⚙️ CodeRabbit configuration file

Review training changes for dataset preprocessing, model path handling, artifact writes, LoRA/DP behavior, GPU memory usage, reproducibility, and cleanup on failure.

Files:

  • src/nemo_safe_synthesizer/training/huggingface_backend.py
src/nemo_safe_synthesizer/data_processing/**/*.py

⚙️ CodeRabbit configuration file

Review for data-contract regressions. Check input/training/test/synthetic naming, group boundaries, token-budget math, record ordering, schema and column validation, nullable dtypes, and deterministic behavior.

Files:

  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
src/nemo_safe_synthesizer/generation/**/*.py

⚙️ CodeRabbit configuration file

Review generation changes for retry loops, stopping conditions, invalid record handling, regex/structured output contracts, backend teardown, memory cleanup, and vLLM assumptions.

Files:

  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
**/*.{md,markdown}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown}: Bold is acceptable only in markdown tables where it's the conventional way to mark header-like cells in the body
Use ## headers to segment markdown sections instead of bold text
Use -- (em-dash) instead of - (hyphen) for asides in markdown

Files:

  • docs/developer-guide/example-generation.md
docs/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/writing-docs.mdc)

docs/**/*.md: Use MkDocs Material admonition syntax (!!! note, !!! warning, ??? tip) for highlighting important information and collapsible sections in documentation
Use MkDocs Material tabs syntax (=== "Label") to present alternative views or language-specific examples in documentation
Use code block syntax with title and highlight line parameters (title="filename", hl_lines="2 3") for code examples in documentation
Use Mermaid diagram syntax (```mermaid flowchart, etc.) for visualizations in documentation

Classify documentation using Diataxis and use MkDocs Material syntax for admonitions, tabs, titled code blocks, and highlights.

docs/**/*.md: Create or edit the .md file under the appropriate docs/ subdirectory.
Add the page to the nav: section of mkdocs.yml so it appears in the sidebar.

Files:

  • docs/developer-guide/example-generation.md
**/*.md

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Do not use decorative bold text in body content; use single backticks for inline code and -- for asides. In Python docstrings, use double backticks and MkDocs autorefs rather than Sphinx roles.

Files:

  • docs/developer-guide/example-generation.md
docs/**

⚙️ CodeRabbit configuration file

Review documentation as MkDocs Material content. Check Diataxis fit, accurate commands, internal links, code fences, and markdown style from STYLE_GUIDE.md.

Files:

  • docs/developer-guide/example-generation.md
🧠 Learnings (6)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-07-27T22:07:22.590Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 673
File: tests/pii_replacer/test_edit.py:327-327
Timestamp: 2026-07-27T22:07:22.590Z
Learning: When tests read structured logging context from Python `logging.LogRecord` instances, don’t access `record.ctx` directly (it isn’t declared on `LogRecord` and will break static typing). Instead, use `getattr(record, "ctx", default)` (or an appropriate fallback) to safely handle cases where `ctx` may or may not be attached. This applies even if Ruff rule `B009` isn’t enabled in the repo.

Applied to files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-07-29T17:12:32.642Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 654
File: tests/config/test_parameters.py:116-118
Timestamp: 2026-07-29T17:12:32.642Z
Learning: In Pydantic validation tests (e.g., models configured with `from_attributes`), when asserting failures from `model_validate(...)`, assert the structured error details (such as `ValidationError.errors()[0]["type"]`, e.g. `"model_attributes_type"`) rather than relying on the human-readable error message text. This keeps tests stable even if wording changes, while still verifying the correct validation rule is triggered.

Applied to files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-08-05T19:07:15.856Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 679
File: tests/conftest.py:89-96
Timestamp: 2026-08-05T19:07:15.856Z
Learning: In the Safe Synthesizer test suite, treat CPU and CUDA installation profiles as the supported pytest collection profiles because they install PyTorch. A bare installation without PyTorch is an incomplete, unsupported profile. GPU-marked test modules may import PyTorch before tests/conftest.py::pytest_collection_modifyitems executes, so do not require that collection hook to prevent such imports.

Applied to files:

  • tests/data_processing/test_prompt_tokens.py
  • tests/llm/test_metadata.py
  • tests/data_processing/test_timeseries_validation.py
  • tests/data_processing/test_assembler.py
  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
📚 Learning: 2026-08-06T15:42:45.969Z
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 703
File: src/nemo_safe_synthesizer/pii_replacer/data_editor/detect.py:356-362
Timestamp: 2026-08-06T15:42:45.969Z
Learning: In NeMo Safe Synthesizer Python code, do not flag diagnostics solely because they report raw DataFrame column names. This is an established convention used in preflight warnings and validation errors. Flag such reporting only when an explicit repository-wide logging or privacy policy requires redaction, or when the diagnostic includes cell values, records, or other sensitive data.

Applied to files:

  • src/nemo_safe_synthesizer/sdk/library_builder.py
  • src/nemo_safe_synthesizer/training/huggingface_backend.py
  • src/nemo_safe_synthesizer/data_processing/timeseries_validation.py
  • src/nemo_safe_synthesizer/generation/timeseries_prompting.py
  • src/nemo_safe_synthesizer/data_processing/assembler.py
  • src/nemo_safe_synthesizer/data_processing/prompt_tokens.py
  • src/nemo_safe_synthesizer/llm/metadata.py
  • src/nemo_safe_synthesizer/generation/timeseries_backend.py
📚 Learning: 2026-06-04T16:14:09.868Z
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 526
File: tests/generation/test_vllm_backend.py:399-509
Timestamp: 2026-06-04T16:14:09.868Z
Learning: In this repo, only apply `pytest.mark.vllm` to smoke tests under `tests/smoke/` that actually run real vLLM GPU generation and therefore require per-file process isolation (e.g., `test-smoke-gpu-*` Makefile targets). Do not apply `pytest.mark.vllm` to unit-style tests under `tests/generation/` that merely import `vllm_backend` but never instantiate a real vLLM engine and never call `.generate()` (GPU not required). Note that `tests/conftest.py` auto-marks these as `unit` via `pytest_collection_modifyitems`, and `vllm` is not among the auto-mark categories—so if a test in `tests/generation/` has `vllm`, it should be treated as a review issue unless it meets the real GPU generation criteria above.

Applied to files:

  • tests/generation/test_timeseries_prompting.py
  • tests/generation/test_timeseries_backend.py
🪛 LanguageTool
docs/developer-guide/example-generation.md

[style] ~451-~451: ‘new records’ might be wordy. Consider a shorter alternative.
Context: ... history and may generate one or more new records. 2. The backend parses and validates ea...

(EN_WORDINESS_PREMIUM_NEW_RECORDS)

🪛 Ruff (0.16.1)
tests/data_processing/test_prompt_tokens.py

[error] 33-33: Possible hardcoded password assigned to argument: "bos_token"

(S106)


[error] 35-35: Possible hardcoded password assigned to argument: "eos_token"

(S106)

🔇 Additional comments (13)
docs/developer-guide/example-generation.md (1)

262-266: LGTM!

Also applies to: 448-462

src/nemo_safe_synthesizer/data_processing/timeseries_validation.py (1)

52-53: LGTM!

Also applies to: 475-487

src/nemo_safe_synthesizer/training/huggingface_backend.py (1)

660-660: LGTM!

Also applies to: 762-764

tests/data_processing/test_timeseries_validation.py (1)

152-166: LGTM!

src/nemo_safe_synthesizer/sdk/library_builder.py (1)

328-329: LGTM!

src/nemo_safe_synthesizer/generation/timeseries_prompting.py (1)

79-82: 🗄️ Data Integrity & Integration

Keep schema-driven numeric coercion. The fixture’s e_id and s_index columns are integer-valued, and make_json_schema assigns them the integer type. The test manually assigns number, so its 0.0 prefix does not represent a production mismatch.

			> Likely an incorrect or invalid review comment.
src/nemo_safe_synthesizer/llm/metadata.py (1)

10-10: LGTM!

Also applies to: 44-46, 64-64, 350-358

src/nemo_safe_synthesizer/data_processing/assembler.py (1)

44-47: LGTM!

Also applies to: 174-178, 202-206, 749-751, 963-985

tests/data_processing/test_assembler.py (1)

779-805: LGTM!

tests/llm/test_metadata.py (1)

734-749: LGTM!

src/nemo_safe_synthesizer/data_processing/prompt_tokens.py (1)

1-53: LGTM!

tests/data_processing/test_prompt_tokens.py (1)

1-89: LGTM!

tests/generation/test_timeseries_prompting.py (1)

12-15: LGTM!

Also applies to: 77-109, 147-148, 187-188

Comment on lines +720 to +723
logger.warning(
f"Group '{state.group_id}' skipped after {state.generation_attempts} attempts without reaching "
f"the configured stop timestamp."
)

@coderabbitai coderabbitai Bot Aug 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove the raw group value from this warning.

If group_id is an account, customer, or device identifier, Line 721 writes source data to operational logs. Log an aggregate or a non-sensitive group ordinal instead. Put attempt counts in extra={}.

Proposed fix
 logger.warning(
-    f"Group '{state.group_id}' skipped after {state.generation_attempts} attempts without reaching "
-    f"the configured stop timestamp."
+    "A time-series group was skipped after reaching the generation attempt limit.",
+    extra={"generation_attempts": state.generation_attempts},
 )

Based on learnings, diagnostics that include cell values warrant a privacy review. As per path instructions, identifiers are high-risk data.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logger.warning(
f"Group '{state.group_id}' skipped after {state.generation_attempts} attempts without reaching "
f"the configured stop timestamp."
)
logger.warning(
"A time-series group was skipped after reaching the generation attempt limit.",
extra={"generation_attempts": state.generation_attempts},
)

Sources: Path instructions, Learnings

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent (review-pr): Confirmed; avoid adding another raw identifier log

The added warning writes the source group value directly to operational logs. Please replace it with a non-sensitive group ordinal and put attempt counts in structured extra fields. The same value also appears in existing warning, debug, progress-summary, and completion logs. Those sites should be cleaned up here or tracked explicitly as follow-up work.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- repository instructions ---'
if [ -f AGENTS.local.md ]; then
  cat AGENTS.local.md
fi
if [ -f STYLE_GUIDE.md ]; then
  sed -n '1,240p' STYLE_GUIDE.md
fi

printf '%s\n' '--- changed logging code and group-id references ---'
rg -n -C 4 --type py \
  '(logger\.(debug|info|warning|error|exception)\(|group_id|next_group)' \
  src/nemo_safe_synthesizer/generation/timeseries_backend.py

printf '%s\n' '--- current PR diff for the backend ---'
git diff --unified=20 HEAD^ HEAD -- src/nemo_safe_synthesizer/generation/timeseries_backend.py

printf '%s\n' '--- related test structure and logging assertions ---'
ast-grep outline tests/generation/test_timeseries_backend.py --items all --type function
rg -n -C 4 --type py \
  '(caplog|logger|GroupState|_process_group_result|_generate_parallel_groups)' \
  tests/generation/test_timeseries_backend.py tests

Length of output: 176620


@binaryaaron, the inspection confirms the issue.

src/nemo_safe_synthesizer/generation/timeseries_backend.py exposes raw group values in:

  • The new attempt-limit warning.
  • The existing invalid-output warnings.
  • The activation debug log.
  • The per-group parallel progress summary.
  • The completion log.
  • The missing-prefix GenerationError.

The fix should stay in this PR. GroupState should carry a stable, one-based group_ordinal assigned from the saved group registry order. The implementation should use that ordinal in human-readable messages. It should place generation_attempts, retry counts, record counts, thresholds, and progress values in extra={}. It must not add group_id to structured fields.

Add focused tests in tests/generation/test_timeseries_backend.py. The tests should use a sentinel group identifier and verify that it is absent from captured warning, debug, summary, completion, and error output. The tests should also verify the expected ordinal and attempt count in structured log context.

Thanks for the guidance.


🧬 Code Graph Analysis Results

src/nemo_safe_synthesizer/generation/timeseries_backend.py

  • Lines 693–764 — _process_group_result
    Increments state.generation_attempts and emits warnings containing the raw state.group_id for attempt-limit failures, zero-valid batches, high-invalid-fraction batches, and consecutive-batch failures. These warnings include attempt counters that are currently interpolated into message strings.

  • Lines 766–816 — _log_parallel_batch_summary
    Builds per-group progress lines containing the raw state.group_id, valid-record counts, and progress totals, then emits them through an informational summary log.

  • Lines 818–952 — _generate_parallel_groups
    Initializes group states and emits logs containing group-related progress. Specifically:

    • Lines 862–865: debug log includes the raw next_group identifier when activating a group.
    • Lines 924–928: completion log includes the raw state.group_id and group completion counts.
    • Lines 941–949: invokes _log_parallel_batch_summary, which logs raw group identifiers as described above.
  • Lines 482–504 — _init_group_state
    Accepts a group_id and uses it to initialize GroupState; its GenerationError message also interpolates the raw group identifier when no prefix exists.

  • Lines 164–205 — GroupState
    Defines group_id as the source TimeSeriesGroupValue and tracks generation_attempts, low_valid_fraction_count, valid/invalid record totals, and completion/failure state. These fields provide the structured values relevant to logging without exposing the identifier.

src/nemo_safe_synthesizer/observability.py

  • Lines 774–789 — get_logger
    Returns the package CategoryLogger, using structlog after observability initialization and a standard-library logger otherwise. This is the logger implementation used by timeseries_backend.py.

✏️ Learnings added
Learnt from: binaryaaron
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 708
File: src/nemo_safe_synthesizer/generation/timeseries_backend.py:720-723
Timestamp: 2026-08-17T17:18:28.668Z
Learning: In `src/nemo_safe_synthesizer/generation/timeseries_backend.py`, `TimeSeriesGroupValue` values originate from the saved training group registry and can be sensitive identifiers. Do not include raw group values in operational logs, structured log fields, or user-facing generation errors. Use a stable non-sensitive group ordinal for diagnostics and put counts, thresholds, and progress metrics in `extra={}`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: zywind
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 703
File: src/nemo_safe_synthesizer/pii_replacer/data_editor/detect.py:356-362
Timestamp: 2026-08-06T15:42:45.969Z
Learning: In NeMo Safe Synthesizer Python code, do not flag diagnostics solely because they report raw DataFrame column names. This is an established convention used in preflight warnings and validation errors. Flag such reporting only when an explicit repository-wide logging or privacy policy requires redaction, or when the diagnostic includes cell values, records, or other sensitive data.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Each group now receives a stable one-based ordinal derived from the saved registry order. Raw group values were removed from warnings, activation/debug output, progress summaries, completion logs, and missing-prefix errors. Counts, thresholds, retries, and progress are emitted through structured extra fields without including group_id. Added tests using a sentinel identifier to verify that it never appears in diagnostics.

reached_stop = self._has_reached_stop_time([r.parsed for r in retained_records if r.parsed is not None])
self._update_group_state(state, retained_records)
patience = self.config.generation.patience
attempt_limit = max(1, state.expected_records) + patience

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent (review-pr): Count consecutive no-progress attempts

generation_attempts increases for every batch, including batches that produce valid records. A group that alternates valid and invalid batches can reach expected_records + patience while still advancing and without ever exhausting the consecutive-invalid patience counter. The threshold-crossing batch may also contain valid records, but the FAILED path does not add that batch to GenerationBatches, so those records are discarded. Track consecutive no-progress attempts and reset the counter after progress, or remove this separate cap and rely on the existing consecutive-failure logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. I replaced the absolute generation_attempts cap with a consecutive no-progress counter. It resets whenever an accepted timestamp advances and only fails after patience consecutive batches without progress. Progress is evaluated after data actions, and the threshold-crossing batch is retained so valid records are not discarded. Added regression coverage for both reset and failure behavior.

@seayang-nv

Copy link
Copy Markdown
Contributor Author

Thanks all the feedback!! Here's a summary of what has changed:

Review feedback addressed

  • Clarified terminology:
    • prefix: incomplete initial JSON record.
    • history: accepted generated records used in later prompts.
    • RecordPromptState: manages prefix/history state.
  • Removed the legacy training-record prefill mechanism.
  • Added typed group metadata and restored source column ordering.
  • Centralized training/generation token-boundary assembly.
  • Replaced configuration casts with validated time-series settings.
  • Applied data actions before updating group history or determining completion.
  • Replaced the absolute generation-attempt cap with consecutive no-progress tracking that resets after timestamp advancement.
  • Ensured threshold-crossing batches are retained instead of silently discarded.
  • Replaced raw group identifiers in logs and errors with stable group ordinals.
  • Moved retry counts, thresholds, and progress metrics into structured logging fields.
  • Added regression coverage for post-processing rejection, retry accounting, and identifier redaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants