You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Forge's full ~16K-line source tree is duplicated verbatim inside praxis-proxy/grid's in-tree forge/ Cargo workspace member. That copy is deliberately kept in place — per grid#30 ("Extract Forge into the standalone praxis-proxy/forge repository"), the recommended delivery plan explicitly defers removal: "Remove the in-tree crate only after all consumers pass parity validation" (step 7, "In-tree Forge deprecation and removal"). grid will file its own tracking issue for that removal/convergence side of the work, since they hold the copy being retired. This issue is the forge-side half: while the duplicate exists, what does forge itself commit to (stability, versioning, compatibility) so grid can eventually take it as a real crate/binary dependency instead of a copy — and what keeps the two copies from silently drifting apart in the meantime?
As of today (11 days after the extraction commit, 9abe12b, 2026-08-07), divergence is already accruing:
One intentional, documented divergence: this repo's own README.md "How Forge relates to other Praxis repositories" section lists the changes made since extraction, including "Added fsync to kubeconfig and template-file atomic writes" — a real, deliberate behavior difference from grid's copy.
One undocumented divergence found while verifying this issue (see Evidence) — a stray .clone() that only exists in forge's copy because grid's workspace lint config picked up clippy::redundant_clone (grid PR #55, 2026-08-13) after the fork point, and forge's own Cargo.toml[lints.clippy] table was never updated to match. Nothing failed CI on either side — the two lint configs just quietly stopped matching.
Neither repository has an automated check that would catch the next non-formatting divergence (a bug fix, a lint-config change, a behavior change) landing in only one copy.
Evidence
Diff methodology: fetched fresh upstream/main for both repos (praxis-proxy/forge@9abe12b and praxis-proxy/grid@2fdaa26), then reformatted both copies of each file with identicalrustfmt --edition 2024 settings (no repo-specific config) before diffing, to separate real code drift from max_width line-wrap noise (this repo has no rustfmt.toml, so rustfmt defaults to max_width = 100; grid's root rustfmt.toml sets max_width = 120).
Repo-wide size check: wc -l src/**/*.rs on this repo's upstream/main totals 16,590 lines — matches the "~16K lines" scope of the duplication.
Two largest files, diffed after common reformatting:
src/config/validate.rs (2,241 lines) vs. grid's forge/src/config/validate.rs: zero differences — fully identical logic, formatting-only drift as expected.
src/stack/engine.rs (1,824 lines) vs. grid's forge/src/stack/engine.rs: 3 real (non-formatting) diff hunks:
#[expect(clippy::disallowed_methods, reason = "forge is synchronous; capture polling has no async runtime")] — present only in grid's copy. This is a downstream consequence of the already-documented clippy.toml divergence (grid's clippy.toml bans std::thread::sleep; this repo's clippy.toml intentionally does not, per this repo's own README note feat: add OTel observability benchmark demo #2) — expected, not a new finding.
src/stack/engine.rs (function around line 559, write_bytes_atomic-style helper): this repo's copy does File::create → write_all → sync_all → drop → rename; grid's copy does a plain std::fs::write(&tmp, bytes) with no fsync. This is the README's documented "Added fsync to ... template-file atomic writes" divergence — confirmed here at the code level.
read_corefile (src/stack/engine.rs, forge line 714): Ok(output.stdout.clone()) in this repo vs. Ok(output.stdout) in grid's copy — an undocumented divergence. Root cause: grid's root Cargo.toml[workspace.lints.clippy] added redundant_clone = "deny" in grid#55 (2026-08-13, six days after the forge extraction); this repo's own Cargo.toml[lints.clippy] table has never picked up that lint, so the redundant clone was never flagged here.
Risk
The two copies have already silently diverged on more than the one documented, intentional change — a lint-config drift produced a real (if harmless) code-level difference within days, with no CI signal on either side.
Nothing prevents the same pattern from happening with an actual bug fix or security-relevant change: a fix landed only in forge won't reach grid's in-tree copy (and vice versa) until someone notices by hand.
The intended end state (grid depends on forge as a real crate/binary instead of vendoring a copy) has no forge-side contract yet: no documented stability/versioning guarantees, no explicit "this is the compatibility surface grid can rely on" statement.
Suggested fix
This repo's half of the two-sided migration (grid#30 owns the removal side):
Document a stability/versioning contract in this repo (e.g. a COMPATIBILITY.md or a section in README.md) covering what grid (and other consumers) can rely on staying stable across releases: the forge.yaml schema version policy (already versioned as forge.praxis.dev/v1alpha1), CLI subcommand/flag stability, exit-code/output-format (--output json) stability, and state-file (state.json) layout stability.
Cross-reference grid#30 from that document (and from this issue) so the duplication is discoverable as a known, tracked, two-sided migration rather than something a future contributor stumbles onto and assumes is an accident.
Consider lint-config parity as an explicit, tracked follow-up: either sync [lints.clippy] in this repo's Cargo.toml against grid's [workspace.lints.clippy] periodically, or document that they're allowed to diverge (this repo is a standalone sync CLI; grid's workspace lints target async code) and accept the resulting code-level drift as a known cost.
Once a tagged release and stability contract exist, grid can replace its in-tree copy with a real dependency on a pinned forge release/tag — closing the loop described in grid#30's "Recommended Delivery" step 7.
Summary
Forge's full ~16K-line source tree is duplicated verbatim inside
praxis-proxy/grid's in-treeforge/Cargo workspace member. That copy is deliberately kept in place — per grid#30 ("Extract Forge into the standalone praxis-proxy/forge repository"), the recommended delivery plan explicitly defers removal: "Remove the in-tree crate only after all consumers pass parity validation" (step 7, "In-tree Forge deprecation and removal").gridwill file its own tracking issue for that removal/convergence side of the work, since they hold the copy being retired. This issue is theforge-side half: while the duplicate exists, what doesforgeitself commit to (stability, versioning, compatibility) sogridcan eventually take it as a real crate/binary dependency instead of a copy — and what keeps the two copies from silently drifting apart in the meantime?As of today (11 days after the extraction commit, 9abe12b, 2026-08-07), divergence is already accruing:
README.md"How Forge relates to other Praxis repositories" section lists the changes made since extraction, including "Addedfsyncto kubeconfig and template-file atomic writes" — a real, deliberate behavior difference from grid's copy..clone()that only exists in forge's copy because grid's workspace lint config picked upclippy::redundant_clone(grid PR #55, 2026-08-13) after the fork point, and forge's ownCargo.toml[lints.clippy]table was never updated to match. Nothing failed CI on either side — the two lint configs just quietly stopped matching.Neither repository has an automated check that would catch the next non-formatting divergence (a bug fix, a lint-config change, a behavior change) landing in only one copy.
Evidence
Diff methodology: fetched fresh
upstream/mainfor both repos (praxis-proxy/forge@9abe12bandpraxis-proxy/grid@2fdaa26), then reformatted both copies of each file with identicalrustfmt --edition 2024settings (no repo-specific config) before diffing, to separate real code drift frommax_widthline-wrap noise (this repo has norustfmt.toml, sorustfmtdefaults tomax_width = 100; grid's rootrustfmt.tomlsetsmax_width = 120).wc -l src/**/*.rson this repo'supstream/maintotals 16,590 lines — matches the "~16K lines" scope of the duplication.src/config/validate.rs(2,241 lines) vs.grid'sforge/src/config/validate.rs: zero differences — fully identical logic, formatting-only drift as expected.src/stack/engine.rs(1,824 lines) vs.grid'sforge/src/stack/engine.rs: 3 real (non-formatting) diff hunks:#[expect(clippy::disallowed_methods, reason = "forge is synchronous; capture polling has no async runtime")]— present only in grid's copy. This is a downstream consequence of the already-documentedclippy.tomldivergence (grid'sclippy.tomlbansstd::thread::sleep; this repo'sclippy.tomlintentionally does not, per this repo's own README note feat: add OTel observability benchmark demo #2) — expected, not a new finding.src/stack/engine.rs(function around line 559,write_bytes_atomic-style helper): this repo's copy doesFile::create→write_all→sync_all→drop→ rename; grid's copy does a plainstd::fs::write(&tmp, bytes)with no fsync. This is the README's documented "Addedfsyncto ... template-file atomic writes" divergence — confirmed here at the code level.read_corefile(src/stack/engine.rs, forge line 714):Ok(output.stdout.clone())in this repo vs.Ok(output.stdout)in grid's copy — an undocumented divergence. Root cause: grid's rootCargo.toml[workspace.lints.clippy]addedredundant_clone = "deny"in grid#55 (2026-08-13, six days after the forge extraction); this repo's ownCargo.toml[lints.clippy]table has never picked up that lint, so the redundant clone was never flagged here.Risk
forgewon't reachgrid's in-tree copy (and vice versa) until someone notices by hand.griddepends onforgeas a real crate/binary instead of vendoring a copy) has no forge-side contract yet: no documented stability/versioning guarantees, no explicit "this is the compatibility surface grid can rely on" statement.Suggested fix
This repo's half of the two-sided migration (
grid#30owns the removal side):COMPATIBILITY.mdor a section inREADME.md) covering whatgrid(and other consumers) can rely on staying stable across releases: theforge.yamlschema version policy (already versioned asforge.praxis.dev/v1alpha1), CLI subcommand/flag stability, exit-code/output-format (--output json) stability, and state-file (state.json) layout stability.[lints.clippy]in this repo'sCargo.tomlagainst grid's[workspace.lints.clippy]periodically, or document that they're allowed to diverge (this repo is a standalone sync CLI; grid's workspace lints target async code) and accept the resulting code-level drift as a known cost.gridcan replace its in-tree copy with a real dependency on a pinnedforgerelease/tag — closing the loop described ingrid#30's "Recommended Delivery" step 7.Severity: Medium