Skip to content

feat(forge): ForgeRecipe + ForgeArtifact Rust types (Phase 1a of #1164)#1170

Merged
joelteply merged 1 commit into
canaryfrom
feat/forge-recipe-types
May 14, 2026
Merged

feat(forge): ForgeRecipe + ForgeArtifact Rust types (Phase 1a of #1164)#1170
joelteply merged 1 commit into
canaryfrom
feat/forge-recipe-types

Conversation

@joelteply
Copy link
Copy Markdown
Contributor

Summary

Implements Phase 1a of the design at docs/architecture/FORGE-RECIPE-AS-ENTITY.md (continuum#1165). Pure Rust value types for the recipe-as-entity layer — no rename of existing TS-side ForgeAlloy yet (Phase 1b), no entity registry hookup yet (Phase 3), no foundry executor yet (Phase 2).

Card

continuum#1169.

What ships

  • ForgeRecipe entity (authored input): identity, prose, methodology, source, pipeline (stages opaque JSON for v1), calibration corpus, top-level quant tiers, evaluation benchmarks, hardware, lineage.
  • ForgeArtifact entity (foundry output): snapshot of recipe fields plus execution outputs (forged_at_ms, duration, params_b, hardware_verified, alloy_hash, results/receipt/integrity opaque JSON for v1). Recipe lineage frozen so later recipe edits cannot retroactively rewrite what the artifact claims.
  • Supporting types: AlloySource, PriorBaseline, CorpusRef (canonical sha256:hex matching admission's content_hash format), QuantTier, BenchmarkDef, AlloyHardware, HardwareProfile.
  • ts-rs bindings to shared/generated/forge/ (9 files + barrel).

Validation

$ cargo test -p continuum-core --features metal,accelerate forge::
test result: ok. 26 passed; 0 failed; 0 ignored

$ cargo test -p continuum-core --features metal,accelerate --test generated_barrel_sync
test result: ok. 8 passed; 0 failed; 0 ignored

26 unit tests covering serde roundtrip, minimal recipe with serde defaults, opaque blob preservation, partial artifact (None results), recipe lineage immutability, ts-rs binding generation. Barrel-sync ratchet from #1137 still green (the 9 new .ts files are correctly referenced from shared/generated/forge/index.ts).

npm run build:ts clean. cargo clippy clean (160 warnings, baseline 163 — 3 below). Hooks ran without --no-verify.

Phase plan (per design doc)

  • Phase 1a (this PR): Rust types + ts-rs bindings + tests
  • Phase 1b: Rename existing TS-side ForgeAlloyForgeArtifact across the 15 referencing files (separate slice)
  • Phase 2: Typed RecipeStage enum (currently Vec<serde_json::Value>) + typed AlloyResults/AlloyReceipt/IntegrityAttestation (currently serde_json::Value blobs)
  • Phase 3: Entity registry registration + forge/run IPC handler

Test plan

  • CI label-pr / validate / WIP green
  • Phase 1b cleanly composes on top (no Rust-side coupling to TS naming)
  • Phase 2 swaps stage opaque JSON → typed enum without breaking serde wire format

🤖 Generated with Claude Code

Implements Phase 1a of the design at docs/architecture/FORGE-RECIPE-AS-ENTITY.md
(continuum#1165). Pure value types only.

What ships:
- ForgeRecipe entity (authored input): identity, prose, methodology,
  source, pipeline (stages opaque JSON for v1), calibration corpus,
  top-level quant tiers, evaluation benchmarks, hardware, lineage.
- ForgeArtifact entity (foundry output): snapshot of recipe fields and
  execution outputs (forged_at_ms, duration, params_b, hardware_verified,
  alloy_hash, results/receipt/integrity opaque JSON for v1). Recipe
  lineage frozen so later recipe edits cannot retroactively rewrite
  what the artifact claims.
- Supporting types: AlloySource, PriorBaseline, CorpusRef (canonical
  sha256 hex matching admission), QuantTier, BenchmarkDef,
  AlloyHardware, HardwareProfile.
- ts-rs bindings to shared/generated/forge/ (9 files plus barrel).

Tests: 26 passing covering serde roundtrip, minimal recipe with
defaults, opaque blob preservation, partial artifact, recipe lineage
immutability, ts-rs binding generation. Barrel-sync ratchet from
PR #1137 still green.

Phase 1b: rename existing TS-side ForgeAlloy to ForgeArtifact
(15 files, separate slice). Phase 2: typed RecipeStage enum and
typed results/receipt/integrity. Phase 3: entity registry plus
forge/run IPC.

Card: continuum#1169.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joelteply joelteply merged commit 9e13bee into canary May 14, 2026
3 checks passed
@joelteply joelteply deleted the feat/forge-recipe-types branch May 14, 2026 15:40
joelteply added a commit that referenced this pull request May 14, 2026
…ct (#1164 Phase 1b) (#1171)

Per the consensus on continuum#1165 (design doc), the existing
single-entity 'ForgeAlloy' name splits across two roles:

- 'ForgeRecipe' (the authored input — what stages, prose, methodology,
  hardware target). All 14 stage-element widget JSDoc references update
  here: 'Maps 1:1 to ForgeAlloy XStage schema' becomes
  'Maps 1:1 to ForgeRecipe XStage schema', and 'Each ForgeAlloy stage
  type' becomes 'Each ForgeRecipe stage type'. The stage widgets are
  recipe-authoring UI; stages live on the recipe side.
- 'ForgeArtifact' (the foundry output — what got measured, hardware
  verified, alloy hash, publication receipt). FactoryStatsWidget's
  'X / Y models have an alloy' panel relabels to 'ForgeArtifact'
  because the panel counts published artifacts, not authored recipes.

Pure rename — no behavior change. The Python forge_alloy/types.py is
untouched (Phase 2 ports those types to Rust as the source of truth);
TS code only references the entity names in JSDoc + UI labels, never
imports them as types.

Validation:
- grep ForgeAlloy in src returns 0 results
- npm run build:ts passes clean
- Hooks ran without --no-verify

Card: continuum#1170 (PR #1170 was Phase 1a; Phase 1b card is created
per the airc queue lane named 1170-pr-phase1b — the CI auto-close
will land on whatever issue # this PR opens against).

Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joelteply added a commit that referenced this pull request May 14, 2026
#1164 Phase 3) (#1180)

Phase 3 of continuum#1164 (design at FORGE-RECIPE-AS-ENTITY.md). TS-side
entity classes that wrap the Rust ts-rs types from #1170 (Phase 1a) +
register both with the data daemon's EntityRegistry so callers can CRUD
forge recipes + artifacts via the standard data/* commands.

What ships:

- src/system/data/entities/ForgeRecipeEntity.ts — class extending
  BaseEntity, mirrors the ForgeRecipe Rust shape with field decorators
  (TextField, JsonField, NumberField). validate() checks required
  fields. Collection: 'forge_recipes'.

- src/system/data/entities/ForgeArtifactEntity.ts — class extending
  BaseEntity, mirrors ForgeArtifact. ForeignKeyField on recipeId +
  unique-indexed alloyHash for content-addressable lookup. validate()
  checks lineage + execution-time fields. Collection: 'forge_artifacts'.

- EntityRegistry.ts — imports both entity classes, instantiates each
  during initializeEntityRegistry() so the decorators register
  metadata, then registerEntity() with the collection name. Same
  pattern as the existing entity bulk.

- shared/generated/entity_schemas.json regenerates with the two new
  collections (sha goes from 8cf44380640f to d5c1cff2a1ed6a6c, entity
  count 55 -> 57).

Field naming subtlety: Rust 'version: string' (semver) collides with
BaseEntity 'version: number' (ORM row version). Renamed to
'recipeVersion: string' on the entity to avoid the conflict + leave
both cross-layer fields workable. Doc-comment notes the drift; Phase
2+ may rename the Rust field for cross-layer alignment.

Validation: npm run build:ts clean. Hooks ran without --no-verify.

Phase 4 (next slice): forge/run IPC handler that takes a recipeId,
runs the foundry pipeline, persists the artifact via data/* commands.

Card: continuum#1180.

Co-authored-by: Test <test@test.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant