Skip to content

feat: deterministic full-namespace TypeScript layout with self-cleaning incremental builds - #237

Merged
danfma merged 6 commits into
mainfrom
005-deterministic-output-layout
Jun 24, 2026
Merged

feat: deterministic full-namespace TypeScript layout with self-cleaning incremental builds#237
danfma merged 6 commits into
mainfrom
005-deterministic-output-layout

Conversation

@danfma

@danfma danfma commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Problem

Generated TypeScript paths were unstable and stale-prone, masking broken imports (observed in a real consumer: a hand-written import { UserProfile } from \"../contracts\" resolved only through a stale orphan barrel; a clean rebuild broke it). Two root causes:

  1. Non-deterministic layout. The output-tree root was the longest common prefix of the currently-present types, so adding/removing a sibling type in another namespace silently relocated unrelated files (a single type collapsed flat to the root; a second type pushed the first into a subfolder).
  2. No orphan pruning. Incremental builds only ever wrote the current set — files a prior run produced but the current run no longer emits were never deleted, so renames/moves left dangling output.

What changed

  • D1 — Full-namespace layout (no stripping). A type's path is its complete kebab-cased C# namespace under the package root (Vigiata.Contracts.Profiles.UserProfileDtovigiata/contracts/profiles/user-profile.ts). The path is now a pure function of the type's own namespace — stable across the type set; local and cross-package converge. Confined to the TS adapter (Dart untouched).
  • D2 — Barrels. Per-namespace leaf barrels stay always-on (the external import unit); the root aggregation barrel (--namespace-barrels) stays opt-in because it defeats tree-shaking, and now mirrors the full C# hierarchy.
  • D3 — Internal direct-file imports. Generated-to-generated references import the defining file directly, never a barrel — structurally avoiding ESM cycles and decoupling internal correctness from barrel emission.
  • Self-cleaning builds. On a successful, non-cache-hit emit the host reconciles the cache manifest and removes orphaned generated files + emptied directories — restricted to transpiler-owned paths, guarded against path traversal, best-effort, and skipped on cache hit / --no-cache / --clean. A layout=full-namespace-v1 fingerprint token invalidates stale caches on upgrade.

Verification

  • .NET: 1191 tests, 0 failed, 7 pre-existing skips; build 0 warnings; CSharpier clean. 11 new tests (OutputLayoutTests, ImportContractTests, DeterministicLayoutScenarioTests, Caching/OrphanPruningTests) + the layout churn across existing assertions.
  • Samples: all 13 regenerated to the new layout; 12/13 green (build + bun test). HelloWorld's pre-existing vite-scaffolding build failure is unrelated and untouched.
  • Dual-agent review (compiler-man + bob) run before commit; findings fixed (empty-output pruning, path-traversal guard, best-effort deletes, DRY).

Docs & traceability

Spec: specs/005-deterministic-output-layout/. Rationale: docs/adr/0025-full-namespace-output-layout.md (supersedes ADR-0006 layout). Baseline matrix + cross-package guide updated.

Follow-up (out of scope)

Downstream consumers (e.g. the Vigiata project) regenerate to the new layout once they consume the updated Metano, and update root-level imports (../contracts) to the namespace subpath (or enable --namespace-barrels).

Copilot AI review requested due to automatic review settings June 24, 2026 02:26

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a deterministic and self-cleaning TypeScript output layout (ADR-0025), where generated files are mapped to their full kebab-cased C# namespaces to ensure path stability, and incremental builds automatically prune orphaned files and empty directories. The review feedback is highly valuable, pointing out a potential NullReferenceException when reading older cache files that lack the 'OutputHashes' property, as well as robustness and platform-specific path comparison issues in the empty directory pruning logic.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/Metano.Compiler/TranspilerHost.cs
Comment thread src/Metano.Compiler/TranspilerHost.cs Outdated

Copilot AI 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.

Pull request overview

This PR changes Metano’s TypeScript target to emit files at deterministic, full-namespace paths (no common-prefix stripping), updates internal import semantics to always reference defining files directly (never namespace barrels), and adds self-cleaning incremental builds that prune orphaned generated outputs based on the cache manifest.

Changes:

  • Switch TS output layout to full C# namespace → nested kebab-case folders; add a layout fingerprint token (layout=full-namespace-v1) to invalidate stale caches.
  • Update internal generated-to-generated imports to target files directly (./file same-ns, #/full/ns/file cross-ns), decoupling correctness from barrel emission and avoiding ESM cycles.
  • Update tests, docs/ADR/specs, and all JS sample targets to match the new layout + import contracts (including package.json#exports subpaths).

Reviewed changes

Copilot reviewed 169 out of 247 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/Metano.Tests/UsingAliasImportTests.cs Updates expected TS output paths under app/… for full-namespace layout.
tests/Metano.Tests/TypeGuardTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ThrowExpressionTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/TargetSpecificNamingTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/SwitchPatternTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/StaticExtensionMemberTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/PrimaryCtorParamCoverageTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/PrimaryConstructorCaptureTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ParamsParameterTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/OutputLayoutTests.cs Adds tests pinning full-namespace output layout + leaf-barrel behavior.
tests/Metano.Tests/NullConditionalInvokeTests.cs Updates expected generated file locations under app/app.ts.
tests/Metano.Tests/NullableTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/NamespaceBarrelsTranspileTests.cs Updates namespace-barrel assertions to reflect full-namespace layout and new aggregation shape.
tests/Metano.Tests/NamedArgumentReorderTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ModuleEntryPointTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/MethodOverloadTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/LambdaTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/JsonSerializerContextTests.cs Updates expected generated file locations under test-app/….
tests/Metano.Tests/InternalMemberEmissionTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/InterfaceTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/InterfaceInheritanceTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/InheritanceTranspileTests.cs Updates expected generated file locations and import expectations for full-namespace layout.
tests/Metano.Tests/ImportContractTests.cs Adds tests pinning the internal direct-file import contract.
tests/Metano.Tests/ImportAliasTests.cs Updates relative import path expectations to reference defining files (not barrels).
tests/Metano.Tests/GenericTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/Frontend/CSharpSourceFrontendTests.cs Updates frontend expectations: LocalRootNamespace now empty under full-namespace layout.
tests/Metano.Tests/ForEachTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ExternalMappingTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ExtensionPropertySetterTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ExtensionCallSiteTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ExceptionTranspileTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/EndToEndOutputTests.cs Updates pinned output and cross-package import paths to new full-namespace barrel paths.
tests/Metano.Tests/DeterministicLayoutScenarioTests.cs Adds scenario tests reproducing the reported stale/orphan + unstable-layout issue.
tests/Metano.Tests/DelegateTypeAliasTests.cs Updates expected generated file locations and cross-package import paths.
tests/Metano.Tests/DelegateEventTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/DefaultParameterValueTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/CtorFieldEmissionTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/CrossPackageImportTests.cs Updates cross-package import expectations to include full-namespace leaf-barrel subpaths.
tests/Metano.Tests/ConstructorOverloadTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/ClassInheritanceTests.cs Updates expected generated file locations under app/….
tests/Metano.Tests/AssemblyTranspileTests.cs Updates expected generated file locations under app/….
targets/js/sample-todo/test/todo-list.test.ts Updates #/… imports to include the sample’s full-namespace subpath.
targets/js/sample-todo/src/sample-todo/todo-list.ts Adds/updates generated sample code under full-namespace directory layout.
targets/js/sample-todo/src/sample-todo/todo-item.ts Adds/updates generated sample code under full-namespace directory layout.
targets/js/sample-todo/src/sample-todo/priority.ts Adds/updates generated sample code under full-namespace directory layout.
targets/js/sample-todo/src/sample-todo/json-context.ts Adds/updates generated sample code under full-namespace directory layout.
targets/js/sample-todo/src/sample-todo/index.ts Adds leaf barrel for the sample’s namespace directory.
targets/js/sample-todo/package.json Updates exports to a namespaced subpath (./sample-todo).
targets/js/sample-todo-service/test/routes.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-todo-service/test/json-context.test.ts Updates imports to match new exports subpath and full-namespace paths.
targets/js/sample-todo-service/test/guards.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-todo-service/test/events.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-todo-service/src/sample-todo/service/todos.ts Updates cross-package import to new sample-todo/sample-todo subpath export.
targets/js/sample-todo-service/src/sample-todo/service/json-context.ts Updates cross-package import to new sample-todo/sample-todo subpath export.
targets/js/sample-todo-service/src/sample-todo/service/index.ts Adds leaf barrel for the service namespace directory.
targets/js/sample-todo-service/src/sample-todo/service/events.ts Adds/updates generated event types + guards under full-namespace layout.
targets/js/sample-todo-service/src/program.ts Updates internal import path to full-namespace subpath.
targets/js/sample-solid-ui/test/components.test.ts Updates test imports to match full-namespace directory layout.
targets/js/sample-solid-ui/src/sample-solid-ui/ui/index.ts Adds leaf barrel for UI namespace directory.
targets/js/sample-solid-ui/src/sample-solid-ui/ui/counter.tsx Adds/updates generated component under full-namespace layout.
targets/js/sample-solid-ui/src/sample-solid-ui/ui/counter-list.tsx Adds/updates generated component under full-namespace layout.
targets/js/sample-solid-ui/src/sample-solid-ui/ui/counter-group.tsx Adds/updates generated component under full-namespace layout.
targets/js/sample-solid-ui/src/program.tsx Updates internal import path to full-namespace subpath.
targets/js/sample-queryable-sqlite/test/product-demo.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/sqlite-translator.ts Extends translator param-name scanning for new ExprTree kinds and errors for unsupported kinds.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/schema.sql Adds sample schema asset under the sample namespace directory.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/product-demo.ts Updates internal type import to full-namespace path.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/index.ts Adds provider leaf barrel under full-namespace layout.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/i-product-repository.ts Updates internal type import to full-namespace path.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/db.ts Updates internal type import to full-namespace path.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/provider/bun-sqlite-product-repository.ts Updates internal imports to full-namespace paths.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/product.ts Adds/updates generated product model under full-namespace layout.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/main.ts Updates internal imports to full-namespace paths.
targets/js/sample-queryable-sqlite/src/sample-queryable-sqlite/index.ts Adds sample leaf barrel under full-namespace layout.
targets/js/sample-queryable-sqlite/package.json Updates main/start/exports to full-namespace subpaths.
targets/js/sample-queryable-arrays/test/array-provider.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-queryable-arrays/src/sample-queryable-arrays/user.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-queryable-arrays/src/sample-queryable-arrays/user-queries.ts Adds/updates generated query helpers under full-namespace layout.
targets/js/sample-queryable-arrays/src/sample-queryable-arrays/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-queryable-arrays/package.json Updates exports to a namespaced subpath (./sample-queryable-arrays).
targets/js/sample-operator-overloading/test/money.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-operator-overloading/src/sample-operator-overloading/no-same-money-currency-exception.ts Adds/updates generated exception under full-namespace layout.
targets/js/sample-operator-overloading/src/sample-operator-overloading/money.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-operator-overloading/src/sample-operator-overloading/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-operator-overloading/src/sample-operator-overloading/currency.ts Adds/updates generated enum under full-namespace layout.
targets/js/sample-operator-overloading/src/program.ts Updates internal imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/shared-kernel/user-id.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/shared-kernel/page-result.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/shared-kernel/page-request.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/shared-kernel/operation-result.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/planning/domain/sprint.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/namespace-barrels.test.ts Updates root aggregation barrel usage to the new root namespace tree shape.
targets/js/sample-issue-tracker/test/json-context.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue-workflow.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue-workflow-matrix.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue-status.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue-mutations.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/issue-id.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/domain/comment.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/application/issue-service.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/application/issue-service-workflows.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/application/issue-queries.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/application/issue-queries-edges.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/issues/application/in-memory-issue-repository.test.ts Updates #/… imports to full-namespace subpaths.
targets/js/sample-issue-tracker/test/helpers.ts Updates helper imports to full-namespace subpaths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/shared-kernel/user-id.ts Adds/updates generated types under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/shared-kernel/page-result.ts Adds/updates generated types under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/shared-kernel/page-request.ts Adds/updates generated types under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/shared-kernel/operation-result.ts Adds/updates generated types under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/shared-kernel/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/planning/domain/sprint.ts Updates internal imports to full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/planning/domain/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/json-context.ts Updates internal imports to full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue.ts Updates internal imports to full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-workflow.ts Adds/updates generated type under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-type.ts Adds/updates generated type under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-status.ts Adds/updates generated type under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-snapshot.ts Updates internal imports to full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-priority.ts Adds/updates generated type under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/issue-id.ts Adds/updates generated type under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/domain/comment.ts Updates internal imports to full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/application/issue-service.ts Updates imports to direct-file full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/application/issue-queries.ts Updates imports to direct-file full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/application/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/application/in-memory-issue-repository.ts Updates imports to direct-file full-namespace paths.
targets/js/sample-issue-tracker/src/sample-issue-tracker/issues/application/i-issue-repository.ts Relocates interface under full-namespace layout and updates imports accordingly.
targets/js/sample-issue-tracker/src/sample-issue-tracker/index.ts Adds sample leaf barrel under full-namespace layout.
targets/js/sample-issue-tracker/src/issues/application/i-issue-repository.ts Removes legacy pre-full-namespace path.
targets/js/sample-issue-tracker/src/index.ts Updates root aggregation barrel to mirror full namespace rooted at package namespace.
targets/js/sample-issue-tracker/package.json Updates exports to include full-namespace subpaths while retaining root barrel.
targets/js/sample-counter-v5/src/views/app-view.tsx Updates #/… imports to full-namespace subpaths.
targets/js/sample-counter-v5/src/sample-counter-v5/stores/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v5/src/sample-counter-v5/stores/counter-store.ts Updates internal imports to full-namespace paths.
targets/js/sample-counter-v5/src/sample-counter-v5/models/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v5/src/sample-counter-v5/models/counter.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-counter-v5/package.json Updates exports to full-namespace subpaths.
targets/js/sample-counter-v5/lib/views/app-view.jsx Updates compiled output imports to full-namespace subpaths.
targets/js/sample-counter-v5/lib/sample-counter-v5/stores/index.js Updates compiled output layout to full-namespace structure.
targets/js/sample-counter-v5/lib/sample-counter-v5/stores/counter-store.js Updates compiled output imports to full-namespace subpaths.
targets/js/sample-counter-v5/lib/sample-counter-v5/models/index.js Updates compiled output layout to full-namespace structure.
targets/js/sample-counter-v5/lib/sample-counter-v5/models/counter.js Updates compiled output layout to full-namespace structure.
targets/js/sample-counter-v4/src/sample-counter-v4/mvu/ui.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/mvu/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/mvu/dom-props.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/mvu/button-props.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/models/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/models/counter.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/inferno/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/inferno/empty-props.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/inferno/dom-extensions.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/components/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v4/src/sample-counter-v4/components/counter-app.ts Updates imports to direct-file full-namespace paths.
targets/js/sample-counter-v4/src/program.ts Updates imports to direct-file full-namespace paths.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/ui.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/ui.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/index.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/index.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/dom-props.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/dom-props.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/button-props.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/mvu/button-props.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/models/index.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/models/index.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/models/counter.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/models/counter.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/index.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/index.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/empty-props.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/empty-props.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/dom-extensions.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/inferno/dom-extensions.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/components/index.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/components/index.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/components/counter-app.js Updates compiled output for full-namespace layout.
targets/js/sample-counter-v4/lib/sample-counter-v4/components/counter-app.d.ts Updates compiled typings for full-namespace layout.
targets/js/sample-counter-v4/lib/program.js Updates compiled entrypoint imports for full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/text.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/row.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/heading.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/column.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widgets/button.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/widget.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/ui.ts Updates widget imports to direct-file paths.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/stateful-widget.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/state-holder.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/build-context.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/mvu/app.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/models/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/models/counter.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/components/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v3/src/sample-counter-v3/components/counter-app.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v3/src/program.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/widgets/text.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/widgets/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/widgets/column.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/widgets/button.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/view-fn.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/state-holder.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/i-widget.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/mvu/app.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/models/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v2/src/sample-counter-v2/models/counter.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-counter-v2/src/program.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v1/src/sample-counter-v1/views/renderer.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v1/src/sample-counter-v1/views/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v1/src/sample-counter-v1/views/i-view.ts Adds/updates generated code under full-namespace layout.
targets/js/sample-counter-v1/src/sample-counter-v1/views/counter-view.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v1/src/sample-counter-v1/presenters/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v1/src/sample-counter-v1/presenters/i-counter-view.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v1/src/sample-counter-v1/presenters/counter-presenter.ts Updates internal imports to direct-file full-namespace paths.
targets/js/sample-counter-v1/src/sample-counter-v1/models/index.ts Adds leaf barrel under full-namespace layout.
targets/js/sample-counter-v1/src/sample-counter-v1/models/counter.ts Adds/updates generated model under full-namespace layout.
targets/js/sample-counter-v1/src/program.ts Updates internal imports to direct-file full-namespace paths.
targets/js/hello-world/lib/program.js Updates compiled output under new directive/header conventions.
src/Metano.Compiler/IR/IrCompilation.cs Updates documentation for LocalRootNamespace semantics under the new layout policy.
src/Metano.Compiler/CSharpSourceFrontend.cs Sets LocalRootNamespace to empty and removes local root namespace computation for TS layout.
src/Metano.Compiler/Caching/CacheKeyBuilder.cs Exposes path-safety helper for pruning and documents deletion safety.
src/Metano.Compiler.TypeScript/TypeScriptTarget.cs Adds layout=full-namespace-v1 into cache fingerprint.
src/Metano.Compiler.TypeScript/Transformation/TypeTransformer.cs Forces empty root stripping for cross-package path computation under full-namespace layout.
src/Metano.Compiler.TypeScript/Transformation/PathNaming.cs Changes internal imports to target defining files directly (not barrels).
src/Metano.Compiler.TypeScript/Commands.cs Documents --no-cache interaction with orphan pruning and --clean.
src/Metano.Compiler.TypeScript/Bridge/IrToTsTypeMapper.cs Aligns cross-package subpath computation with full-namespace layout.
src/Metano.Build/build/Metano.Build.targets Documents reduced need for MetanoClean due to self-pruning incremental outputs.
specs/005-deterministic-output-layout/quickstart.md Adds end-to-end validation steps for deterministic layout + pruning + import contract.
specs/005-deterministic-output-layout/data-model.md Defines the conceptual entities/contracts behind deterministic layout and pruning.
specs/005-deterministic-output-layout/contracts/pruning-contract.md Adds normative pruning contract documentation.
specs/005-deterministic-output-layout/contracts/path-mapping.md Adds normative type→path mapping contract documentation.
specs/005-deterministic-output-layout/contracts/import-contract.md Adds normative internal/external import contract documentation.
specs/005-deterministic-output-layout/checklists/requirements.md Captures spec readiness checklist for this feature.
specs/001-project-baseline-evolution/baseline/feature-support-matrix.md Updates baseline matrix to reflect new layout + pruning guarantees.
docs/cross-package.md Updates cross-package import documentation for full-namespace layout and internal direct-file imports.
docs/adr/0025-full-namespace-output-layout.md Adds ADR describing the decision and its consequences.
CLAUDE.md Updates active feature plan pointer to spec 005.
.specify/feature.json Points Spec Kit feature directory to spec 005.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 145ec48ffe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Metano.Compiler/TranspilerHost.cs
danfma added 6 commits June 23, 2026 23:45
…ental builds

Map each generated type to its complete kebab-cased C# namespace under the
package root instead of stripping a longest-common-prefix "root namespace".
The prior layout was data-dependent: adding or removing a sibling type in
another namespace silently relocated unrelated files, and orphaned outputs
were never deleted - together masking broken imports (a consumer's
`../contracts` resolving only through a stale barrel).

- The path is now a pure function of a type's own namespace (no stripping),
  stable across the type set; local and cross-package converge.
- Internal generated-to-generated references import the defining file
  directly, never a barrel - structurally avoiding ESM cycles and decoupling
  internal correctness from barrel emission.
- Per-namespace leaf barrels stay always-on; the root aggregation barrel
  (`--namespace-barrels`) stays opt-in and now mirrors the full hierarchy.
- Incremental builds self-prune: orphaned generated files and emptied
  directories are removed by reconciling the cache manifest, restricted to
  transpiler-owned paths and guarded against path traversal; skipped on a
  cache hit / --no-cache / --clean and only after a successful emit.
- A layout-version token in the cache fingerprint invalidates stale caches
  on upgrade.

Spec under specs/005-deterministic-output-layout; rationale in ADR-0025.
…e layout

Regenerate every C#-backed sample under the new full-namespace layout and
re-point hand-written consumers (bun tests, app entries) at the
full-namespace subpaths. Update the SampleIssueTracker namespace-barrels
test for the now package-rooted aggregation tree, and rebuild the
metano-runtime dist that several samples build against.

All regenerated samples build, and every sample that ships bun tests is
green. HelloWorld's pre-existing vite-scaffolding build failure is
unrelated and untouched.
Samples were regenerated and verified green (12/13; HelloWorld's pre-existing
vite-scaffolding failure is unrelated), so T012/T024 are done, not blocked.
…space layout

Add feature-support-matrix rows tracing the full-namespace layout and orphan
pruning to ADR-0025 with code+test references, and update the cross-package
import-resolution guide for full-namespace paths, internal direct-file imports,
and the opt-in (non-tree-shakable) root aggregation barrel. Closes feature 005
documentation debt (T026/T027).
…ailures

Address PR review feedback on the pruning step:
- Guard `previous?.OutputHashes` directly so pruning never depends on the
  cache structural-validity contract (defensive; TryRead already rejects
  manifests without OutputHashes).
- Make the empty-directory probe best-effort: catch I/O and access failures
  from `Directory.EnumerateFileSystemEntries` instead of letting them abort
  an otherwise successful build.
- Compare output-tree paths with the host filesystem's case sensitivity so
  the empty-directory walk is correct on case-insensitive Windows/macOS.
… is removed

When an emit produces zero files (the last [Transpile] type was removed), the
TypeScript CLI skipped the package.json reconciliation, leaving exports that
advertise subpaths whose barrels were just pruned. Run the reconciliation on an
empty output set too, but only when a package.json already exists - so stale
transpiler exports are pruned without scaffolding package.json for a project
that never produced output. Addresses PR review feedback.
@danfma
danfma force-pushed the 005-deterministic-output-layout branch from 1cd9868 to f9530f7 Compare June 24, 2026 02:45
@danfma
danfma merged commit 78eaaf6 into main Jun 24, 2026
2 checks passed
@danfma
danfma deleted the 005-deterministic-output-layout branch June 24, 2026 02:49
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.

2 participants