refactor: use project-named state file and store prompt/params directly
- State filename now derives from config: cards.bulkgen.yaml produces .cards.bulkgen-state.yaml instead of .bulkgen.state.yaml - Store resolved prompt text and extra params directly in state file instead of hashing them, making state files human-readable - Only file input contents remain hashed (SHA-256) - Thread project_name through builder and CLI - Remove hash_string() and _extra_hash() helpers - Update .gitignore pattern to .*.bulkgen-state.yaml
This commit is contained in:
parent
870023865d
commit
0ecf1f0f9e
7 changed files with 98 additions and 82 deletions
|
|
@ -1,4 +1,4 @@
|
|||
"""Incremental build state tracking via ``.bulkgen.state.yaml``."""
|
||||
"""Incremental build state tracking via ``.<project>.bulkgen-state.yaml``."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -8,16 +8,23 @@ from pathlib import Path
|
|||
import yaml
|
||||
from pydantic import BaseModel
|
||||
|
||||
STATE_FILENAME = ".bulkgen.state.yaml"
|
||||
|
||||
def state_filename(project_name: str) -> str:
|
||||
"""Return the state filename for a given project name.
|
||||
|
||||
For a config file named ``cards.bulkgen.yaml`` the project name is
|
||||
``cards`` and the state file is ``.cards.bulkgen-state.yaml``.
|
||||
"""
|
||||
return f".{project_name}.bulkgen-state.yaml"
|
||||
|
||||
|
||||
class TargetState(BaseModel):
|
||||
"""Recorded state of a single target from its last successful build."""
|
||||
|
||||
input_hashes: dict[str, str]
|
||||
prompt_hash: str
|
||||
prompt: str
|
||||
model: str
|
||||
extra_hash: str = ""
|
||||
extra_params: dict[str, object] = {}
|
||||
|
||||
|
||||
class BuildState(BaseModel):
|
||||
|
|
@ -35,14 +42,9 @@ def hash_file(path: Path) -> str:
|
|||
return h.hexdigest()
|
||||
|
||||
|
||||
def hash_string(value: str) -> str:
|
||||
"""Compute the SHA-256 hex digest of a string."""
|
||||
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def load_state(project_dir: Path) -> BuildState:
|
||||
def load_state(project_dir: Path, project_name: str) -> BuildState:
|
||||
"""Load build state from disk, returning empty state if the file is missing."""
|
||||
state_path = project_dir / STATE_FILENAME
|
||||
state_path = project_dir / state_filename(project_name)
|
||||
if not state_path.exists():
|
||||
return BuildState()
|
||||
with state_path.open() as f:
|
||||
|
|
@ -52,20 +54,13 @@ def load_state(project_dir: Path) -> BuildState:
|
|||
return BuildState.model_validate(raw)
|
||||
|
||||
|
||||
def save_state(state: BuildState, project_dir: Path) -> None:
|
||||
def save_state(state: BuildState, project_dir: Path, project_name: str) -> None:
|
||||
"""Persist build state to disk."""
|
||||
state_path = project_dir / STATE_FILENAME
|
||||
state_path = project_dir / state_filename(project_name)
|
||||
with state_path.open("w") as f:
|
||||
yaml.dump(state.model_dump(), f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
|
||||
def _extra_hash(params: dict[str, object]) -> str:
|
||||
"""Hash extra target parameters (width, height, etc.) for change detection."""
|
||||
if not params:
|
||||
return ""
|
||||
return hash_string(str(sorted(params.items())))
|
||||
|
||||
|
||||
def is_target_dirty(
|
||||
target_name: str,
|
||||
*,
|
||||
|
|
@ -98,10 +93,10 @@ def is_target_dirty(
|
|||
if prev.model != model:
|
||||
return True
|
||||
|
||||
if prev.prompt_hash != hash_string(resolved_prompt):
|
||||
if prev.prompt != resolved_prompt:
|
||||
return True
|
||||
|
||||
if prev.extra_hash != _extra_hash(extra_params):
|
||||
if prev.extra_params != extra_params:
|
||||
return True
|
||||
|
||||
for dep_path in dep_files:
|
||||
|
|
@ -131,7 +126,7 @@ def record_target_state(
|
|||
|
||||
state.targets[target_name] = TargetState(
|
||||
input_hashes=input_hashes,
|
||||
prompt_hash=hash_string(resolved_prompt),
|
||||
prompt=resolved_prompt,
|
||||
model=model,
|
||||
extra_hash=_extra_hash(extra_params),
|
||||
extra_params=extra_params,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue