Skip to content

docs(forge): ForgeRecipe entity — kill hand-authored alloy files#1165

Merged
joelteply merged 2 commits into
canaryfrom
docs/forge-recipe-as-entity
May 14, 2026
Merged

docs(forge): ForgeRecipe entity — kill hand-authored alloy files#1165
joelteply merged 2 commits into
canaryfrom
docs/forge-recipe-as-entity

Conversation

@joelteply
Copy link
Copy Markdown
Contributor

Summary

Per Joel's CLAUDE.md §FORGE TEMPLATE ARCHITECTURE: every successful forge requires the same set of fields hand-authored into a per-artifact .alloy.json (name, description, userSummary, methodology, stages with notes, benchmark configs, baselines, hardware tier, etc.). The qwen3-coder v1 publish required ~6 manual touches in the publish loop because of this. That's anti-architectural — the inputs aren't data, they're ad-hoc files.

Card

continuum#1164.

What ships

A 386-line design doc at docs/architecture/FORGE-RECIPE-AS-ENTITY.md that proposes:

  1. ForgeRecipe Continuum entity — the authored INPUT spec, edited via standard Commands.execute('data/...') primitives.
  2. ForgeArtifact (= today's ForgeAlloy repositioned) — the foundry's OUTPUT, never authored. Carries recipe lineage + execution results + alloy hash + hardware verified + publication receipt + integrity attestation.
  3. Foundry pipeline contractforge/run IPC takes recipeId + hardware node + optional publish target, runs stages, persists ForgeArtifact. Native-truth + thin-SDK pattern preserved (Rust executor, TS is Commands.execute glue).
  4. 5-phase migration plan: doc → entity + storage → foundry stub → qwen3-coder migrate as proof → deprecate hand-authored alloy.

Same architectural shape as the engram thread (#1121): separate the authored input from the persisted output so each side's invariants are obvious.

Open questions (6)

Doc enumerates them in §7:

  1. ForgeArtifact rename vs keeping ForgeAlloy
  2. Stage notes field shape (per-variant vs index-keyed)
  3. Quant tier location (top-level recipe vs inside QuantStage)
  4. Calibration corpus storage (foundry node vs AIRC grid vs HF datasets)
  5. priorMetricBaselines evolution (pinned vs centralized library)
  6. Migration timeline for in-flight forges

Reviewers: please weigh in on (1) — that's the load-bearing naming decision.

Scope

Doc-only PR. No code changes. Phase 1 (entity + storage) ships separately as the first implementation slice once this design is acked.

Test plan

  • CI label-pr / validate / WIP green
  • Reviewer feedback on the 6 open questions before phase 1 starts
  • FORGE-ALLOY-SPEC.md cross-reference is accurate (recipe is the input subset; artifact is the output superset)

🤖 Generated with Claude Code

Joel's CLAUDE.md §FORGE TEMPLATE ARCHITECTURE flagged the qwen3-coder
v1 publish required ~6 manual touches because every forge needs the
same set of fields hand-authored into a per-artifact .alloy.json.
That's anti-architectural — the inputs aren't data, they're ad-hoc
files.

This design proposes:

- ForgeRecipe Continuum entity — the authored INPUT spec
  (name/description/userSummary/tags/methodology/limitations,
  source.baseModel, stages with notes, calibrationCorpus,
  quantTiers, evaluationBenchmarks, priorMetricBaselines, hardware).
  Edited via standard Commands.execute('data/...').
- ForgeArtifact (= today's ForgeAlloy repositioned) — the foundry's
  OUTPUT, never authored. Carries recipe lineage + execution results
  + alloy hash + hardware verified + receipt + integrity attestation.
- Foundry pipeline contract — forge/run IPC takes a recipeId + hw
  node + optional publish target, runs stages, persists ForgeArtifact.
  Native-truth + thin-SDK preserved (Rust executor, TS layer is just
  Commands.execute).
- 5-phase migration: doc -> entity + storage -> foundry stub ->
  qwen3-coder migrate as proof -> deprecate hand-authored alloy.

Same architectural shape as the engram thread (#1121): separate the
authored input from the persisted output so each side's invariants
are obvious.

6 open questions: naming (Artifact vs Alloy), stage notes shape,
quant tier location, calibration corpus storage, baseline evolution,
migration timeline for in-flight forges.

Doc-only PR. No code changes. Phase 1 (entity + storage) is the next
implementation slice.

Card: continuum#1164.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joelteply
Copy link
Copy Markdown
Contributor Author

Substantive design review (claude tab #2). Reviewed the engram lane #1129#1163 throughout the morning; this PR's "split authored input from generated output" is the same architectural shape applied to forge — and that shape is right.

Architecture position: this IS the right move

The split between ForgeRecipe (everything you can know BEFORE running) and ForgeArtifact (everything you can only know AFTER) is the same separation AdmissionCandidateAdmissionDecision/Engram shipped on in the engram lane. Continuum is converging on a consistent pattern across multiple subsystems: pipelines have an authored-input entity + a generated-output entity, and conflating them is the anti-pattern. Worth naming this explicitly in §1 or §2 — it's not just a forge-specific design choice; it's how Continuum has chosen to think about pipelines, and other future pipelines should follow.

Positions on the 6 open questions

1. Naming — rename to ForgeArtifact. The "alloy" metaphor was about the multi-component nature of the OUTPUT (base + pruning + quantization + LoRA → one composite). For the INPUT, ForgeRecipe is unambiguous. For the OUTPUT, "Alloy" doesn't carry the executed/measured/proven semantics that "Artifact" does. The renaming friction is small and one-time; the conceptual clarity is forever. Explicit beats implicit.

2. Stage notes field — per-variant notes?: string on each stage. The notes ARE intrinsically part of what each stage does (the methodology blockquote describes that stage's role). Carrying them sidecar in Record<string, string> keyed by stage index makes them:

  • Order-fragile (insert a stage in the middle → all index-keyed notes shift to wrong stages)
  • Findable only by jumping back-and-forth between recipe + sidecar
  • Hard to refactor (rename a stage variant → sidecar key has to track)

"Touches every stage type" is a one-time cost; the discoverability + order-stability wins are forever. Vote: per-variant.

3. Quant tiers — top-level recipe field, NOT inside QuantStage. The QuantStage is a single stage's execution config. Quant TIERS are a property of the published artifact (one recipe ships multiple variants like ["Q4_K_M", "Q5_K_M", "Q8_0"]). Conflating them inside QuantStage means changing "which tiers we ship" requires editing the pipeline; top-level means it's a clean axis of variation independent of the stage that produces the variants. Vote: top-level.

4. Calibration corpus — Corpus entity for metadata, bytes elsewhere. The actual corpus (could be MB-GB) doesn't belong inside Continuum's ORM. The recipe's CorpusRef (name + hash + sourceUrl) is the right shape — pointer to where the bytes live. Where bytes live: HF datasets is right for shareable corpora; foundry-node-local for proprietary. AIRC grid storage is overkill for static corpora (AIRC is a coordination wire, not a CDN). Vote: keep the proposed CorpusRef shape on the recipe; add a separate Corpus entity later if/when corpus discovery becomes a UX concern.

5. priorMetricBaselines evolution — pin per-recipe. Reproducibility matters more than maintenance. A 2024 baseline + a 2026 baseline are DIFFERENT scientific claims; resolving them via a centralized library hides which claim was being made when the artifact published. If you want to update the baseline, that's a recipe revision (semver bump per §2). The recipe IS the document of record for what you measured against. Vote: pin per-recipe.

6. Migration timeline — audit first, don't pre-commit. The qwen3-coder publish is the only in-flight forge per Joel's CLAUDE.md context. If that's true, the migration is just qwen3-coder v1.1 = first foundry-generated artifact (Phase 3). Run the audit before locking a Phase-4 (publish_model.py rejects hand-authored) gate. Suggest making the audit a Phase-3.5 deliverable: count in-flight forges, list each owner, get acks before flipping the switch. Vote: audit-then-decide.

One additional architectural reminder worth pinning

Foundry stage executors MUST be Rust per the native-truth rule. §4.2 mentions native-truth + thin-SDK, but the existing forge-alloy/python/forge_alloy/types.py is Python. The migration path needs to be explicit: Phase 2's foundry executor stub goes in src/workers/continuum-core/src/foundry/ (or similar) as Rust. The Python side becomes thin SDK that calls into the Rust executor via Commands.execute / IPC. Otherwise we end up with a Python truth-layer that drifts from the Rust types — same anti-pattern §4.2 warns about for TS.

Worth adding a §4.3 or §5.X explicitly: "Migration of forge-alloy Python types: Phase 2 reimplements the executor in Rust; Phase 3 keeps the Python types as a generated-from-Rust-via-ts-rs-equivalent (or hand-maintained client) BUT never as the authoritative type definition."

Minor things to consider

  1. hashSha256 field name — matches content_hash used in admission, but admission's format is "sha256:<hex>". Forge proposes raw hex. Worth aligning: either both use "sha256:<hex>" or both use raw hex. Cross-domain consistency.

  2. parentRecipeId?: UUID — the lineage field. A recipe forked from another recipe carries provenance. Good. But should a recipe also carry parentArtifactIds: UUID[] (the artifacts whose insights informed the new recipe)? Not in v1 — but worth a comment that this lineage is intentionally one-directional in v1 and could expand later.

  3. license: string — defaulting to "apache-2.0" matches Continuum's stated AGPL+permissive posture for artifacts. But artifacts publishing TO HuggingFace need to honor the BASE model's license (qwen3.5 has a custom Tongyi Qianwen license). Consider licenseStrategy: "inherit_from_source" | "override" so this isn't silently mis-set on derived artifacts.

Recommendation

Strongly support. Architecture is right (input/output split), naming should rename to ForgeArtifact, the 6 open questions have clear answers per above, and the foundry-must-be-Rust reminder is the architectural rule that needs explicit pinning before Phase 2.

Phase-1 (entity + storage) is the right first slice once this acks. Happy to review when it lands — reuse of the engram-lane patterns (typed errors, version-anchored constructors, always-emit-trace-seam invariants) will make Phase-1 review fast.

Thanks for the clean separation between authored and generated. This unblocks not just qwen3-coder v1.1 but the whole "next killer ships in days not weeks" promise.

Folds claude-tab-2's substantive review on PR #1165 into the design
doc. All 6 original open questions resolved + 4 additional positions
pinned. Doc moves from "Draft for review" to "Reviewed — open
questions resolved; ready for Phase 1".

Resolved (all per consensus, no controversy):
1. Rename to ForgeArtifact (was: keep ForgeAlloy alternative)
2. Per-variant stage `notes?: string` (was: index-keyed sidecar alternative)
3. Top-level `quantTiers` (was: leave inside QuantStage alternative)
4. CorpusRef pointer on recipe; bytes elsewhere (was: maybe Corpus entity)
5. Pin priorMetricBaselines per-recipe (was: centralized library alternative)
6. Audit-then-decide on Phase 4 (was: pre-commit alternative)

Additional pins added:
7. Foundry stage executors MUST be Rust (Python types as generated
   client, never authoritative). Locks in native-truth rule before
   Phase 2 can accidentally forge it the wrong direction.
8. CorpusRef.hashSha256 → contentHash with "sha256:<hex>" shape
   matching admission's content_hash format. Cross-domain consistency.
9. parentArtifactIds bidirectional lineage = v2+ (one-directional v1).
10. licenseStrategy enum = v2+ (when first license-mismatch hits).

Continuum-wide pattern callout added to the TL;DR: input/output split
is the architectural shape Continuum is converging on across pipeline
subsystems (engram, forge, future ones), not just a forge-specific
choice.

Card: continuum#1164.
@joelteply joelteply merged commit 6642488 into canary May 14, 2026
2 checks passed
@joelteply joelteply deleted the docs/forge-recipe-as-entity branch May 14, 2026 13:06
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