Skip to content

feat(cli,data,engine)!: align projects on the manifest layout with canonical parameters - #252

Draft
Emin017 wants to merge 93 commits into
mainfrom
emin/project-alignment
Draft

feat(cli,data,engine)!: align projects on the manifest layout with canonical parameters#252
Emin017 wants to merge 93 commits into
mainfrom
emin/project-alignment

Conversation

@Emin017

@Emin017 Emin017 commented Sep 2, 2026

Copy link
Copy Markdown
Member

What Changed

  • Canonical flat parameter vocabulary (chipcompiler/data/parameter_keys.py): parameter keys are now flat snake_case (design, top_module, frequency_max, ...) across PDK templates, in-memory Parameters.data, every read site, and the persisted workspace config. GUI/RPC payloads — including the positional geometry aliases — are converted at the boundary so creation-time GUI parameters are effective instead of landing as inert duplicates. Breaking: the long keys ("Design", "Top module", ...) are no longer produced or consumed.
  • Workspace configuration moves to TOML: home/parameters.jsonhome/ecc.toml ([design]/[pdk]/[flow]/[params], [pdk].config stored workspace-relative), written atomically via tomli-w and read via tomllib. Legacy workspaces migrate on open at load_workspace: normalize → rewrite → verify → delete the JSON, falling back to the in-memory copy and retrying on the next open if the rewrite fails; when both files exist the TOML wins with a shadowing warning. Signoff packaging bundles it as initial/ecc.toml.
  • Project manifest layout: project.json is generated on virgin first run and keeps run status write-back; runs resolve from the manifest with hints for legacy runs/ layouts; ecc param is rejected in manifest projects; manifest presence is detected lexically and manifest flow ranges are validated against the canonical chain. Effective-config layering (GUI-flat / hybrid / base) is unified between ecc check and ecc run and validated before execution.
  • Continue existing runs (engine/reconcile.py, cli/project/run_*): persisted flows are reconciled against flow targets; running against an existing workspace serializes on the project lock, revalidates run state inside the lock, bounds resume to the target, locks fresh runs before publish, and commits terminal step state after fallible post-success work. Failed fresh runs stay artifact-free.
  • ecc migrate: upgrades legacy runs/ projects to the manifest layout — exact preview with confirmation, per-workspace transactional move anchored to confirmed filesystem identities via renameat2 (all-or-nothing per workspace, symlink sources refused), idempotent resume with collision reporting, serialized on a project lock. All migration-only functions are marked typing_extensions.deprecated (static-only, category=None: pyright/IDE-visible, zero runtime warnings) to mark them as sunset machinery.
  • Review-round hardening: config-write containment against symlinked targets, malformed flow ledgers degraded to recorded errors instead of crashing, wrong-type/undecodable state reads rejected, JSON booleans rejected at manifest integer boundaries, huge MPC index integers kept out of float conversion, generated filelists made fully frozen and reloadable.
  • Tool wrappers (Yosys, ECC-Tools, DreamPlace, Sizer) read the canonical keys; ecc-tools harden QoR area gates read the canonical mpc key.
  • Tests: new suites for manifest discovery/run, effective config, config layers, migration (plan/guards/safety), flow continuation, reconcile, workspace config, legacy migration, and RPC parameter creation; existing fixtures flipped to canonical keys; test_overwrite_guard.py split along ownership boundaries.

Scope

Select the areas touched by this PR:

  • CLI - command behavior, Typer command surface, output formats, or workspace commands.
  • Flow/runtime - workspace lifecycle, EngineFlow, step execution, logs, metrics, or artifacts.
  • EDA integration - Yosys, ECC-Tools, DreamPlace, KLayout, PDKs, or native/runtime wrappers.
  • Build/package - Nix, PyInstaller, wheels, uv.lock, or release artifacts.
  • CI/release - GitHub Actions, version checks, changelog, or release automation.
  • Tests/docs only

Runtime And Packaging Impact

  • No runtime or packaging impact
  • CLI output or machine-readable contract changed
  • Workspace layout, flow state, or artifact paths changed
  • Native toolchain or wrapper behavior changed
  • ecc-tools or ecc-dreamplace dependency changed
  • PyInstaller, Nix, or release artifact changed

Notes:

  • New runtime dependency tomli-w>=1.0 (pure-Python TOML writer) for atomic home/ecc.toml writes; uv.lock updated. No ecc-tools/ecc-dreamplace version change.
  • Machine-readable contract: new ecc migrate command (JSON statuses such as already_migrated, migration_collision); project.json manifest; workspace.create example payloads now use canonical flat keys.
  • Workspace layout: manifest projects keep workspaces at the project root instead of runs/<id>; home/ecc.toml replaces home/parameters.json (legacy files migrate on open); signoff bundles initial/ecc.toml instead of parameters.json.
  • Wrapper behavior: Yosys/ECC-Tools/DreamPlace/Sizer builders, checklists, and metrics read canonical snake_case parameter keys.

Validation

List the commands you ran. Mark checks that are not applicable as N/A.

  • uv run pytest test/ — run as pytest test/ --ignore=test/examples/test_soc.py (CI parity, ics55 PDK cloned per CI setup): 1789 passed, 3 skipped, 4 xfailed
  • uv run ruff check chipcompiler test — all checks passed
  • uv run ruff format --check chipcompiler test — 261 files already formatted
  • PyInstaller smoke: ecc --help, ecc --version, ecc version --json
  • Nix smoke: nix run .#cli -- --help
  • Manual flow smoke:
  • Other:

Skipped checks and reason:

  • PyInstaller smoke: covered by the CI "Build PyInstaller Bundle" job; not run locally.
  • Nix smoke: Nix flake untouched on this branch, so N/A.
  • Manual flow smoke: covered by test/integration/test_harden_flow.py::test_ics55_gcd in the suite above.

Checklist

  • I kept the change scoped to ECC.
  • I updated docs or user-facing CLI text where behavior changed.
  • I included lockfile or version metadata updates when dependencies changed.
  • I documented any submodule updates and why they are needed.
  • I did not include local caches, virtual environments, or generated build outputs.
  • I explained skipped validation and remaining risk.

@Emin017 Emin017 added this to the 0.1.0-alpha.12 milestone Sep 2, 2026
@Emin017 Emin017 changed the title Emin/project alignment feat(cli,data,engine)!: align projects on the manifest layout with canonical parameters Sep 2, 2026
…as TOML

Canonical parameter vocabulary is now flat snake_case across the Python
layer: PDK templates, in-memory Parameters.data, all read sites, and the
workspace's persisted configuration. Workspace configuration moves from
home/parameters.json to home/ecc.toml ([design]/[pdk]/[flow]/[params]),
written atomically via tomli-w and read via tomllib; [pdk].config is
stored workspace-relative.

Legacy workspaces migrate on open at load_workspace: the long-key
parameters.json is normalized, rewritten to home/ecc.toml, verified, and
deleted; when both files exist the TOML wins with a shadowing warning;
a failed rewrite falls back to the normalized in-memory copy and retries
on the next open.

The RPC creation path converts GUI flat payloads (including the
positional geometry aliases) through the parameter_keys module, so
creation-time GUI parameters are effective instead of landing as inert
duplicates. Layout-edit publish normalizes the native long-key
parametersPatch at the merge boundary and writes the TOML store.

Run start re-establishes home.json pointers (flow/checklist/parameters)
after home.reset(). Signoff packaging reads [params] from home/ecc.toml
and bundles it as initial/ecc.toml.
- dreamplace builder reads the TOML workspace config via load_parameter
  instead of json_read (which silently returned {} on the new store)
- GUI scalar margin broadcasts to both core axes so it survives the
  floorplan margin shape check
- die.size now drives the floorplan die_builder (mode die_size +
  width/height) instead of being ignored
- a malformed home/ecc.toml never falls back to a stale legacy
  parameters.json; TOML precedence is unconditional
- save_workspace_config validates [flow] before writing and converts
  tomli_w serialization failures (e.g. legacy null payloads) into a
  False return so migration fallback paths stay reachable
- [flow] start/end accept canonical step names only; display aliases
  translate at the manifest/RPC boundary
…ayouts

Projects carrying a project.json manifest (GUI projects) now resolve run
directories through the manifest workspaces table: a single non-archived
workspace auto-selects, --run-id matches workspace_id or the declared
path tail, and unknown or ambiguous ids fail with workspace_not_declared
listing the declared ids. Broken manifests surface as manifest_invalid.
ecc check validates the manifest instead of demanding ecc.toml.

Legacy runs/ projects (no project.json) keep their existing behavior and
now carry a non-fatal legacy_layout_detected warning record on
run/check/status disclosing ecc migrate.
ecc param subcommands fail with an explicit param_requires_ecc_toml
error in project.json projects (the manifest param backend is a designed
follow-up), and ecc init no longer pre-creates the empty runs/ container
so init'd projects classify as virgin.
…tatus

A first run in a virgin project creates the workspace at the project
root (<root>/<run_id>) and generates project.json (schema v1, GUI draft
objectives, preset-derived start/end display names, initial running
status, default qor_baseline) via write-if-absent; --set values stay
run-scoped and never enter the manifest. Losing the generation race
discards ours and continues read-only.

Runs in manifest projects layer base_design + parameter_patch beneath
--set, seed the flow range from the workspace entry's start/end display
names, and finalize the entry's status (success/failed) through the
shared read-modify-write helper; undeclared single-segment run ids
create <root>/<id> with a workspace_not_registered warning and no
manifest entry, while nested or absolute ids fail invalid_run_id.
Flow targets are now ranges over the canonical harden chain, persisted
per workspace in home/ecc.toml [flow] (preset form for CLI-born
workspaces, start/end canonical names for GUI-born ones, seeded at
creation; non-contiguous selections degrade to first..last with a log
note). Workspace files carry canonical names only.

engine/reconcile.py compares the target with flow.json pairwise under
home/workspace.lock: a proper-prefix target appends the missing suffix
as Unstart and adopts the new target; equal or target-prefix shapes
no-op or resume; a stale [flow] is repaired in place (range-compared, so
preset and start/end forms of the same range are not churned); divergent
flows fail with flow_mismatch before any write.
ecc run against an existing workspace no longer fails run_exists; it
reconciles the flow target (project ecc.toml [flow] over home/ecc.toml
[flow]; manifest projects use the workspace's own section) with the
persisted flow.json and: no-ops when everything succeeded, resumes from
the first non-Success step, extends a proper-prefix target by appending
the suffix as Unstart (prefix outputs untouched, tool deps checked only
for executed steps), and fails divergent flows with flow_mismatch
suggesting --overwrite or a new --run-id before any mutation.

--set on an existing run is rejected with set_requires_fresh_run and
[params] in ecc.toml degrades to a params_ignored_on_existing_run
warning. Workspace mode (--workspace) reconciles against the
workspace's own [flow] before rerun selection, so extension works there
too.
ecc migrate upgrades a legacy project to the manifest layout: it prints
the plan and asks for confirmation on a TTY (--yes otherwise), moves
each runs/<id> workspace to the project root, rebases home.json
pointers, regenerates tool configs via refresh_workspace_config, and
registers every migrated workspace in a generated project.json with
start/end and status derived from the persisted flow.json. A rebase
failure rolls that workspace back (rename back, all-or-nothing per
workspace); a run id colliding with a root entry is skipped with
migration_collision while others proceed; runs/ is removed once empty.
The command is idempotent: an already migrated project reports
already_migrated, and a partially migrated one resumes by appending only
the missing manifest entries.
Review follow-ups:

- Hybrid projects (both ecc.toml and project.json) now layer the
  manifest base beneath the ecc.toml values instead of silently
  discarding it, and a declared entry still seeds the creation-time
  flow range.
- Manifest-assembled configs carry origin_verilog (as the rtl fallback)
  and origin_def into workspace creation.
- An existing run directory whose flow ledger has no steps fails with
  invalid_flow_json instead of reporting a no-op success.
- Migration rollback restores workspace content, not just the
  directory location: home.json pointers are reverse-rebased and tool
  configs regenerated at the source. Manifest registration failures
  now fail the command (exit 1) instead of a warning, and losing the
  manifest creation race falls back to appending entries.
- Losing the virgin manifest generation race reloads the winning
  manifest and writes back status only when the workspace is declared.
- load_manifest validates mpc entries with the GUI parser's rules.
- The run-target resolution, manifest config assembly, and existing-run
  reconcile wiring move to cli/project/run_prepare.py, and the migrate
  handler to cli/project/migrate.py, returning command_handlers/
  project.py under the module-size budget.
- The CommandInput protocol members become read-only properties, which
  is what the frozen input dataclasses actually provide; this removes
  the pre-existing execute_command variance error class rather than
  adding a new instance for migrate.
- normalize_parameter_dict exposes the dict-shaped normalize path with
  a plain dict return so neither ty's isinstance narrowing (dict[Never]
  keys) nor a narrowed/delared union poisons downstream .get calls.
- ProjectConfig gains manifest_parameters/manifest_origin_def fields
  instead of dynamically assigned attributes.
- Manifest objectives normalization mirrors the GUI parser exactly:
  primary defaults to timing, directions keep only maximize/minimize
  entries from the source.
code-simplifier pass over the new modules (mapping-table payload
split/merge, _flow_step_template reuse, _find_workspace_entry
extraction, stdlib import hoisting) plus the final codex review fixes:

- target-prefix reconciles are unconditional no-ops even when steps
  beyond the target are unfinished; a real crash window (suffix Unstart
  + stale [flow]) repairs then resumes
- hybrid projects (ecc.toml + project.json) use the project [flow] as
  the existing-run target and read the manifest base layer only after
  the real run name resolves
- ecc migrate rejects a broken/identity-less ecc.toml before moving
  anything, and failed workspaces register as failed (the persisted
  state string is "Incomplete", not "Imcomplete")
- virgin manifest writes are fully atomic (temp file + link
  create-if-absent); generated base_design.parameters includes the
  ecc.toml [params] resolution on both the virgin and migrate paths
- legacy workspace migration seeds [flow] from the persisted flow.json
  first/last steps (invalid derivations degrade to absent)
- layout-edit publish renders home/ecc.toml through the shared
  render_workspace_config, restoring workspace-relative pdk.config and
  dropping the stray [params._flow]
- ecc config surfaces manifest selection errors; ecc check in a
  manifest project with an ambiguous selector fails with
  workspace_not_declared instead of a misleading checked record
- [flow] preset values are validated against the known builders
- target-prefix reconciles no longer rewrite the workspace [flow] at
  all: extra persisted steps are kept untouched and reconcile never
  widens intent, so back-to-back runs both no-op instead of the second
  one resuming the suffix
- ecc migrate rejects semantic config errors before moving anything
  (bad params, missing design/pdk identity, unknown pdk/preset), while
  filesystem existence checks stay out of the migration path
- ecc check surfaces manifest selection errors for hybrid projects too
  (ecc.toml present), not only manifest-only ones
- legacy flow seeding tolerates a non-object flow.json instead of
  crashing the workspace open
The integration conftest and the filelist/stdio/requests fixtures still
wrote legacy long keys, which landed as inert duplicates after the
canonical flip and broke the full uv run pytest gate.
A non-contiguous flowConfig.steps selection previously wrote the
explicit steps into flow.json while [flow] widened to first..last, so
the two stores contradicted each other and the next reconcile saw a
divergence. One shared resolver now widens both stores to the same
contiguous range with the log note.
A target-prefix workspace (persisted flow covers more than the target)
now adopts the effective target section into home/ecc.toml [flow] when
its persisted section is stale, per AC-13. Adoption always writes the
effective target itself, never a range derived from the ledger, so
extra persisted steps are kept but never become the target; execution
remains an unconditional no-op.
resolved_base_parameters now projects the ecc.toml-resolved canonical
payload through parameters_to_geometry, so positional values surface as
the wizard's aliases (utilitization, margin, die_width) instead of
backend nested subtrees.
…y commands

Unknown top-level keys in a GUI flat payload are now logged before
persistence (kept for forward compatibility, never silently shadowing
canonical ones). The single-segment run-id validator is shared with the
read-only manifest discovery path, so nested or absolute --run-id
values fail with invalid_run_id instead of workspace_not_declared.
Hybrid projects now fill missing identity/pdk/rtl fields from the
manifest base before validation (explicit ecc.toml values always win),
layer the workspace entry's parameter_patch after run-name resolution,
seed the entry flow range only when the project ecc.toml has no flow
target (project [flow] outranks the manifest entry), and emit a
config_layer_diverged warning when the two layers disagree.
- Registration failure now rolls the whole unregistered batch back to
  runs/ (previously moved workspaces were stranded at the root and a
  retry reported "already migrated")
- An existing project.json is validated semantically before the first
  rename, so a malformed manifest fails before any move
- Workspace-local pdk config paths are rebased before the moved
  workspace loads (both legacy parameters.json and home/ecc.toml), so
  they never point back at the old source
- D7 status precedence: any Incomplete marks the workspace failed,
  outranking Ongoing/Pending
update_manifest now re-reads before replacing and re-applies the mutator
to the freshest document when an unrelated change lands mid-update, so
concurrent GUI edits are never silently overwritten. Project-level
updated_at is owned by each mutator: status write-back now touches only
the target entry's status and updated_at, and failed write-backs
surface as manifest_write_back_failed warning records without failing
the run.
…config

load_workspace_config now derives an absent [flow] from the persisted
flow.json first/last steps (D5a fallback), and TOML parse/flow
validation failures propagate instead of collapsing into an empty
payload, so runs report workspace_config_invalid rather than
invalid_workspace (and never fall back to stale legacy JSON).
- Fresh-run preparation and execution moves from
  cli/command_handlers/project.py to cli/project/run_prepare.py
  (execute_fresh_run), along with the manifest-mode check handler; the
  handler is back to input/result mapping at 547 lines
- The legacy parameters migration and the flow selection resolver move
  from data/workspace/__init__.py to data/workspace_config.py, next to
  the store they operate on
- The RPC creation converter and the layout-edit TOML staging helpers
  move to the new runtime/workspace_config_io.py

New modules stay under the size budget; no CLI startup import cost
(verified: no chipcompiler.data modules on the app import path).
Two round-12 review fixes:

- find_config_path now detects lexical presence (lexists) instead of
  readability: a symlink loop, directory, or stat-failing ecc.toml is
  PRESENT, so the read that follows raises ConfigUnreadableError and the
  project fails loud instead of being silently demoted to the manifest
  layer;
- manifest workspace selection matches the DECLARED path tail from the
  raw document again: canonicalizing workspace_path for execution must
  not rename the selector — a symlinked declared path is found by its
  declared name, and the canonical target name is not accepted as an
  alias the document never spelled.
…ases

Two round-13 review fixes, same lexical-presence/declared-spelling class
as the previous round:

- find_manifest now uses lexists like find_config_path: a directory,
  symlink loop, or dangling symlink at project.json classifies the
  project as manifest and fails load_manifest with manifest_invalid,
  instead of silently demoting to the virgin/legacy layout;
- an undeclared run id that canonically lands on a DECLARED workspace's
  path is refused with workspace_not_declared naming the declared
  selector — resuming or overwriting that workspace under an alias the
  document never spelled would bypass its registration and status
  write-back.
…ration destination, validate effective manifest parameters
…eflight

- Take the workspace lock before create_workspace makes the run target
  discoverable (held through seeding and engine execution), so a
  concurrent run can never classify the fresh target as existing and
  win the race to execute it; the lock file moves to a sibling path
  (<workspace>.lock) so it predates and survives the creation.
- Split the existing-workspace run path out of run_prepare (700-line
  budget) into run_existing.
- Validate manifest-layer parameter values in the shared
  validate_effective preflight so ecc check reports them too; values
  overridden by explicit ecc.toml/--set keys stay inert.
- Treat --overwrite as a fresh run during preflight (the target is
  wiped and recreated) and reject symlinked home/home.json in the
  existing-target guard.
…st validation

- run_steps' full-ledger completeness check no longer fails target-bound
  resumes (the persisted ledger may legitimately be wider than the
  reconciled target; fresh runs keep the strict default).
- Validate and present manifest parameters on the canonical projection
  so GUI-flat geometry aliases (utilitization, margin, aspect_ratio)
  face registry range checks and show up in config --resolved; raw
  non-numeric values now fail instead of silently skipping range checks.
- Reject candidate patches against a missing workspace parameters
  config instead of recreating it from the patch alone.
- Avoid double-closing the project fd when the migration destination
  identity check fails.
A present-but-undecodable or wrong-shaped home/flow.json previously
degraded to the empty-ledger defaults, so the migration registered a
fabricated Synth..Harden range and not_started status that contradict
the persisted ledger — the next run would fail flow_mismatch against
its own manifest. The ledger read now distinguishes absent (migrates
with not_started defaults, a workspace that never ran) from malformed
(blocked with migration_unsupported and left under runs/, including a
step record without a name).
A resume plan containing only blocked workspaces reported
already_migrated with exit 0 while those workspaces were still under
runs/ — the early return now requires no blocked entries too. A present
flow.json without a valid steps field is likewise malformed (the engine
always writes one), not an empty ledger, so it is blocked instead of
fabricating Synth..Harden defaults.
…xecution

Round-14 targeted review fixes:

- the explicit --workspace path moved out of the command handler into
  run_workspace.py: everything from the locked re-probe through
  execution holds the sibling workspace lock, and the default resume is
  bounded to the reconciled target — a wider persisted ledger is never
  re-executed or invalidated past the target end (rerun gains a
  `through` bound on run_resume/run_from and bounded_resume_names);
- ecc migrate serializes each move with an active execution of that
  workspace via its existing sibling lock (opened only when present, so
  discovery skips *.lock artifacts and a clean migration still removes
  an empty runs/);
- a virgin run that loses the manifest generation race binds to the
  winner only when the winning entry declares this id at THIS path —
  a same-id winner elsewhere receives neither the run nor its status;
- rollback reports truthfully: a workspace moved back with unrestored
  pointers/config is migration_rollback_incomplete, not rolled_back;
- --set values that override a different lower-layer value (manifest
  base or ecc.toml [params]) now emit config_layer_diverged on the same
  canonical projection as the other layer pairs.
An --workspace run against a nonexistent path took the sibling lock
before failing, leaving the parent directories and a stray <name>.lock
behind. The existence check now precedes lock acquisition — a command
with nothing to run never mutates the tree. rerun.py's new through/last
bounds use explicit Optional annotations, and the workspace-run wiring
tests materialize their virtual workspace on disk to match the locked
execution design.
Every migration-only function now carries a static
typing_extensions.deprecated marker (category=None: pyright/IDE-visible,
zero runtime warnings — no DeprecationWarning spam on every workspace
open). Two families: the legacy runs/ -> manifest layout machinery
(migrate.py, migrate_plan.py, migrate_fs.py helpers, project_migrate_lock,
existing_workspace_execution_lock, the migrate command handler) and the
legacy parameters.json -> ecc.toml config migration
(migrate_legacy_parameters, legacy_parameters_fallback,
legacy_parameters_path, workspace config-filename migration).

Deliberately unmarked: flock_file (shared with the permanent
.manifest.lock writer coordination), _derive_flow_from_ledger (also the
permanent hand-broken-config fallback), is_workspace_config (recognizes
both formats, not migration machinery).
…t remnants

Rebase follow-up onto main 1f910c3 (#111 Yosys LEC, #250 obsolete flow
config removal, #251 Sizer legalization): the canonical chains now carry
Timing optimization and postRouteLec and no longer contain fixFanout.

- MANIFEST_FLOW_STEPS, PRESET_MANIFEST_RANGE (incl. the new synthesis_lec
  preset), the migration display map, and the workspace step-name alias
  table all cover the new steps;
- the removed netlist-opt step's leftover mapping table entry, fixfanout
  config write, checklist class, runner function, and metrics builder are
  deleted (main removed the feature); yosys_lec reads the canonical lec
  parameter key;
- ecc-tools submodule follows main's pin (f6ee10aa, a descendant of the
  branch's logger-throw pin);
- tests updated to the new chains; the two ics55 integration tests fail
  locally only because the Sizer binary is absent — main fails them
  identically with the PDK linked (verified on an origin/main worktree).
@Emin017
Emin017 force-pushed the emin/project-alignment branch from 4de21cf to fcb93fb Compare September 3, 2026 01:42
…et path

On filesystems that recycle inodes immediately (overlayfs on CI), a
fresh replacement directory can land on the moved workspace's freed
inode, so the anchored child_stat identity proof wrongly counted it as
recovered — the rollback then reported a clean failure without the
incomplete marker, and the unconfirmed object was treated as restored.
A missing target is now always an incomplete rollback: no object is
touched, and the user inspects manually. The proof had no realistic
trigger and no test coverage.
The workspace's persisted configuration moved from home/ecc.toml to
home/params.toml, so a project has exactly one human-editable TOML (the
project-root ecc.toml) and the machine-managed snapshot no longer shares
its name. Content, sections, and the canonical vocabulary are unchanged;
the parameters.json migration path now targets params.toml directly (the
ecc.toml name never shipped — no compatibility layer for it).

The three sites that hardcoded home/ecc.toml now go through
workspace_config_path so the name is single-sourced. When both
params.toml and a legacy parameters.json exist in a workspace, the TOML
still wins — and run/check/status now append a workspace_config_shadowed
warning record at the command boundary, telling the user the JSON is
inert and safe to delete.
Codex review of 8620894 found four gaps:

- the agent foundation extractor still preferred home/ecc.toml, so a
  params.toml-only workspace extracted with unknown design/PDK context —
  it now prefers params.toml through workspace_config_path, falling back
  to the legacy JSON;
- the shadow warning probed ctx.run_dir even for run --workspace — it
  now probes the explicit workspace target, and uses lexists so a
  dangling legacy link still counts as shadowing (the spec'd semantics);
- the canonical filename was not fully single-sourced: signoff
  packaging, the runtime snapshot's pointer fallback, and reconcile's
  adopt-failure message all built the path by hand — all now go through
  workspace_config_path.
…ale names

Round-2 review of the params.toml rename found two leftovers: the signoff
collector's [params] read still built the path by hand (now through
workspace_config_path like the packaging point), and the deprecated
markers plus merge docstring in workspace_config.py still named ecc.toml
as the migration target.
The round-3 review's P3 sweep: the deprecated marker in
workspace/__init__.py, candidate_materialization.py's docstring, the
gcd example trees (README.md, README.cn.md, both ics55flow scripts),
and a legacy-readonly test's comment and variable still named the
workspace config file ecc.toml. All now say params.toml. The
project-level ecc.toml references are intentionally untouched.
Round-4 P3 sweep: two test docstrings, one comment, and one test name
still said ecc.toml where the workspace config (home/params.toml) is
meant; all renamed. No behavior change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant