refactor: simplify distillation data layout
This commit is contained in:
+4
-19
@@ -29,22 +29,7 @@ text-to-cad/assets/
|
||||
text-to-cad/benchmarks/*.gif
|
||||
text-to-cad/models/
|
||||
|
||||
# DesignIR teacher data and runtime artifacts
|
||||
designir-pipeline/workspace/teacher/inbox/*
|
||||
!designir-pipeline/workspace/teacher/inbox/.gitkeep
|
||||
designir-pipeline/workspace/teacher/evidence/*
|
||||
!designir-pipeline/workspace/teacher/evidence/.gitkeep
|
||||
designir-pipeline/workspace/reconstruction/inbox/*
|
||||
!designir-pipeline/workspace/reconstruction/inbox/.gitkeep
|
||||
designir-pipeline/workspace/reconstruction/designir/*
|
||||
!designir-pipeline/workspace/reconstruction/designir/.gitkeep
|
||||
designir-pipeline/workspace/reconstruction/output/*
|
||||
!designir-pipeline/workspace/reconstruction/output/.gitkeep
|
||||
designir-pipeline/workspace/acceptance/inbox/*
|
||||
!designir-pipeline/workspace/acceptance/inbox/.gitkeep
|
||||
designir-pipeline/workspace/acceptance/reports/*
|
||||
!designir-pipeline/workspace/acceptance/reports/.gitkeep
|
||||
designir-pipeline/workspace/promotion/candidates/*
|
||||
!designir-pipeline/workspace/promotion/candidates/.gitkeep
|
||||
designir-pipeline/workspace/promotion/replay_validated/*
|
||||
!designir-pipeline/workspace/promotion/replay_validated/.gitkeep
|
||||
# Local distillation inputs and run artifacts. Only output/ is versioned.
|
||||
designir-pipeline/input/*
|
||||
!designir-pipeline/input/.gitkeep
|
||||
designir-pipeline/runs/
|
||||
|
||||
@@ -96,33 +96,27 @@ Schema 位于:
|
||||
将待处理的 STEP/STP 文件放入:
|
||||
|
||||
```text
|
||||
designir-pipeline/workspace/teacher/inbox/
|
||||
designir-pipeline/input/
|
||||
```
|
||||
|
||||
完整运行目录:
|
||||
蒸馏目录只保留三层:
|
||||
|
||||
| 阶段 | 路径 |
|
||||
| --- | --- |
|
||||
| 教师 STEP 输入 | `workspace/teacher/inbox/` |
|
||||
| 私有几何证据 | `workspace/teacher/evidence/` |
|
||||
| Reconstruction Agent 输入 | `workspace/reconstruction/inbox/` |
|
||||
| 参数化重建结果 | `workspace/reconstruction/designir/` |
|
||||
| 独立重建 STEP | `workspace/reconstruction/output/` |
|
||||
| Acceptance Agent 输入 | `workspace/acceptance/inbox/` |
|
||||
| 验收报告 | `workspace/acceptance/reports/` |
|
||||
| 经验候选 | `workspace/promotion/candidates/` |
|
||||
| 跨案例回放验证 | `workspace/promotion/replay_validated/` |
|
||||
| 正式经验库 | `workspace/promotion/promoted/library.json` |
|
||||
| 失败与能力缺口 | `workspace/quarantine/` |
|
||||
| 路径 | 用途 | Git |
|
||||
| --- | --- | --- |
|
||||
| `designir-pipeline/input/` | 原始教师 STEP/STP | 不提交 |
|
||||
| `designir-pipeline/runs/` | 证据、DesignIR、重建件、验收、草稿和失败记录 | 不提交 |
|
||||
| `designir-pipeline/output/library.json` | 通过确定性校验的经验库 | 提交 |
|
||||
|
||||
详细说明见 [`designir-pipeline/workspace/README.md`](designir-pipeline/workspace/README.md)。
|
||||
`runs/` 内部由程序按需创建 `evidence`、`designir`、`rebuilt`、
|
||||
`acceptance`、`review` 和 `quarantine`。目录层级只负责整理文件;两个
|
||||
Agent 的读写边界由程序和合同控制。
|
||||
|
||||
详细说明见 [`designir-pipeline/README.md`](designir-pipeline/README.md)。
|
||||
|
||||
批量提取教师证据:
|
||||
|
||||
```bash
|
||||
designir-pipeline/scripts/cad-experience extract-folder \
|
||||
--input designir-pipeline/workspace/teacher/inbox \
|
||||
--output designir-pipeline/workspace/teacher/evidence
|
||||
designir-pipeline/scripts/cad-experience extract-folder
|
||||
```
|
||||
|
||||
蒸馏得到的经验必须同时通过几何一致性、特征语义、参数可编辑性和修改稳定性验收。两个 Agent 都无权直接发布经验,最终晋升由确定性策略执行。
|
||||
@@ -187,7 +181,7 @@ text-to-cad/.venv/bin/python -m unittest \
|
||||
```bash
|
||||
text-to-cad/.venv/bin/python \
|
||||
designir-pipeline/skills/cad-experience-builder/scripts/cad_experience.py \
|
||||
audit designir-pipeline/workspace/promotion/promoted/library.json
|
||||
audit designir-pipeline/output/library.json
|
||||
```
|
||||
|
||||
## 当前边界
|
||||
|
||||
+29
-20
@@ -26,30 +26,32 @@ removed. `scripts/designir_pipeline.py anti-cheat` rejects source STEP
|
||||
references, imported B-Reps, embedded meshes, topology references, and generator
|
||||
source that calls STEP import APIs.
|
||||
|
||||
## Workspace
|
||||
## Data layout
|
||||
|
||||
Runtime data is role-separated under `workspace/`:
|
||||
|
||||
For the exact input, process, acceptance, and output locations, see
|
||||
[`workspace/README.md`](workspace/README.md).
|
||||
The operator-facing layout has only three directories:
|
||||
|
||||
```text
|
||||
workspace/
|
||||
teacher/inbox/ uploaded STEP/STP files
|
||||
teacher/evidence/ private deterministic evidence
|
||||
reconstruction/inbox/ evidence packets for Agent A
|
||||
reconstruction/designir/ authored DesignIR 2.0
|
||||
reconstruction/output/ independently rebuilt STEP
|
||||
acceptance/inbox/ manifests visible to Agent B
|
||||
acceptance/reports/ geometry and editability reports
|
||||
promotion/candidates/ untrusted generalized methods
|
||||
promotion/replay_validated/
|
||||
promotion/promoted/ deterministic published experience
|
||||
quarantine/ unsupported vocabulary and failed cases
|
||||
designir-pipeline/
|
||||
input/ drop source STEP/STP files here
|
||||
runs/ all private process artifacts
|
||||
output/library.json verified experience consumed at runtime
|
||||
```
|
||||
|
||||
Only `.gitkeep` files are versioned in runtime directories. Teacher geometry,
|
||||
private evidence, generated parts, and reports stay local.
|
||||
`input/` and `runs/` are ignored by Git. Only the deterministic result in
|
||||
`output/` is versioned. The pipeline creates these private run directories as
|
||||
needed:
|
||||
|
||||
| Local path | Purpose |
|
||||
| --- | --- |
|
||||
| `runs/evidence/` | Deterministic evidence extracted from source STEP. |
|
||||
| `runs/designir/` | DesignIR authored by Reconstruction Agent. |
|
||||
| `runs/rebuilt/` | STEP rebuilt without access to source STEP. |
|
||||
| `runs/acceptance/` | Independent geometry and editability reports. |
|
||||
| `runs/review/` | Sanitized semantic batches and untrusted drafts. |
|
||||
| `runs/quarantine/` | Failures and unsupported feature vocabulary. |
|
||||
|
||||
The shallow directory structure is for usability, not authorization. Agent and
|
||||
compiler access is enforced by their contracts and by anti-cheat checks.
|
||||
|
||||
## DesignIR 2.0
|
||||
|
||||
@@ -87,9 +89,16 @@ by deterministic code after several independent cases pass.
|
||||
|
||||
## Commands
|
||||
|
||||
Use the CAD Python environment:
|
||||
Drop files into `input/`, then use the CAD Python environment:
|
||||
|
||||
```bash
|
||||
scripts/cad-experience extract-folder
|
||||
scripts/cad-experience prepare
|
||||
# The semantic distiller writes runs/review/experience-draft.json.
|
||||
scripts/cad-experience publish \
|
||||
--draft runs/review/experience-draft.json
|
||||
scripts/cad-experience audit output/library.json
|
||||
|
||||
../text-to-cad/.venv/bin/python scripts/designir_pipeline.py validate part.designir.json
|
||||
../text-to-cad/.venv/bin/python scripts/designir_pipeline.py compile \
|
||||
part.designir.json --output rebuilt.step
|
||||
|
||||
@@ -7,9 +7,9 @@ meaningfully editable.
|
||||
|
||||
## Allowed inputs
|
||||
|
||||
- Teacher STEP from the protected teacher vault.
|
||||
- Candidate DesignIR.
|
||||
- Reconstructed STEP.
|
||||
- Teacher STEP from protected `input/`.
|
||||
- Candidate DesignIR from `runs/designir/`.
|
||||
- Reconstructed STEP from `runs/rebuilt/`.
|
||||
- Deterministic compiler version.
|
||||
- Modification test contract.
|
||||
|
||||
@@ -36,10 +36,9 @@ Parametric behavior:
|
||||
|
||||
## Required output
|
||||
|
||||
Write one machine-readable acceptance report with separate geometry,
|
||||
Write one machine-readable report under `runs/acceptance/` with separate geometry,
|
||||
feature-semantic, parameter-editability, and stability sections. Never collapse
|
||||
the result into an unexplained similarity score.
|
||||
|
||||
The agent may recommend pass, fail, or quarantine. Only the deterministic
|
||||
publisher changes promotion state.
|
||||
|
||||
|
||||
@@ -7,4 +7,7 @@ reconstruction_output_access: read
|
||||
acceptance_report_access: write
|
||||
publish_access: denied
|
||||
instructions: acceptance-agent.md
|
||||
|
||||
teacher_input_path: input
|
||||
designir_input_path: runs/designir
|
||||
rebuild_input_path: runs/rebuilt
|
||||
report_output_path: runs/acceptance
|
||||
|
||||
@@ -8,7 +8,7 @@ geometry.
|
||||
|
||||
## Allowed inputs
|
||||
|
||||
- One private evidence packet produced by the ingestion service.
|
||||
- One private evidence packet from `runs/evidence/`.
|
||||
- The user modification request.
|
||||
- Promoted generalized experience.
|
||||
- The DesignIR schema and supported operation vocabulary.
|
||||
@@ -24,7 +24,7 @@ geometry.
|
||||
|
||||
## Required output
|
||||
|
||||
Write one `*.designir.json` containing:
|
||||
Write one `runs/designir/*.designir.json` containing:
|
||||
|
||||
- family and reconstruction status;
|
||||
- coordinate system and datums;
|
||||
@@ -46,4 +46,5 @@ If the vocabulary is insufficient, emit
|
||||
Request `isolated-rebuild`. Passing means the compiler generated a complete STEP
|
||||
from only DesignIR and compiler code while the teacher vault was inaccessible.
|
||||
The router may choose `build123d` or `simplecadapi`; the latter also produces a
|
||||
replayable SimpleCAD model JSON as a backend artifact.
|
||||
replayable SimpleCAD model JSON as a backend artifact. Put rebuild artifacts in
|
||||
`runs/rebuilt/`.
|
||||
|
||||
@@ -8,3 +8,6 @@ reconstruction_output_access: request_only
|
||||
acceptance_report_access: denied
|
||||
publish_access: denied
|
||||
instructions: reconstruction-agent.md
|
||||
input_path: runs/evidence
|
||||
designir_output_path: runs/designir
|
||||
rebuild_output_path: runs/rebuilt
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# STEP reconstruction benchmark
|
||||
|
||||
Each case stores only a protected teacher STEP in Git LFS. DesignIR,
|
||||
reconstructed STEP, acceptance reports, and perturbation artifacts are produced
|
||||
at runtime outside the case directory.
|
||||
|
||||
These two teachers were migrated from the retired Exact Base fixtures. Their old
|
||||
copied-B-Rep specifications and generated outputs were intentionally removed.
|
||||
They are now held-out truth for independent DesignIR reconstruction.
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"case_id": "015133",
|
||||
"teacher": "teacher.step",
|
||||
"purpose": "held_out_designir_reconstruction"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"case_id": "015240",
|
||||
"teacher": "teacher.step",
|
||||
"purpose": "held_out_designir_reconstruction"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,11 +10,10 @@ published library and require repeated support before promoting any experience.
|
||||
|
||||
## Required workflow
|
||||
|
||||
1. Put source `.step` or `.stp` files in
|
||||
`workspace/teacher/inbox/`. Only deterministic ingestion and Agent B may
|
||||
access this vault.
|
||||
2. Parse every new, content-unique STEP into visible private JSON under
|
||||
`workspace/teacher/evidence/`:
|
||||
1. Put source `.step` or `.stp` files directly in `input/`. Git ignores this
|
||||
directory; only deterministic ingestion and Agent B may access it.
|
||||
2. Parse every new, content-unique STEP into private JSON under
|
||||
`runs/evidence/`:
|
||||
|
||||
```bash
|
||||
../../scripts/cad-experience extract-folder
|
||||
@@ -26,11 +25,11 @@ published library and require repeated support before promoting any experience.
|
||||
../../scripts/cad-experience prepare
|
||||
```
|
||||
|
||||
4. Read `workspace/promotion/candidates/semantic-batch.json` completely. Act as the semantic
|
||||
4. Read `runs/review/semantic-batch.json` completely. Act as the semantic
|
||||
distiller: compare families, parameter roles, datum roles, canonical
|
||||
reconstruction stages, feature cardinality classes, relations, prior
|
||||
vocabulary, failure rules, and validation targets; then author
|
||||
`workspace/promotion/candidates/experience-draft.json` using
|
||||
`runs/review/experience-draft.json` using
|
||||
`references/llm-review-contract.md`.
|
||||
|
||||
Propose methods, invariants, and family-level `reconstruction_grammar`
|
||||
@@ -44,7 +43,7 @@ published library and require repeated support before promoting any experience.
|
||||
|
||||
```bash
|
||||
../../scripts/cad-experience publish \
|
||||
--draft ../../workspace/promotion/candidates/experience-draft.json
|
||||
--draft ../../runs/review/experience-draft.json
|
||||
```
|
||||
|
||||
The publisher recomputes support from the private corpus, rejects numeric
|
||||
@@ -55,14 +54,14 @@ published library and require repeated support before promoting any experience.
|
||||
|
||||
```bash
|
||||
python scripts/cad_experience.py audit \
|
||||
../../workspace/promotion/promoted/library.json
|
||||
../../output/library.json
|
||||
```
|
||||
|
||||
7. Query only the published library for creation, modification, or rebuilding:
|
||||
|
||||
```bash
|
||||
python scripts/cad_experience.py query \
|
||||
../../workspace/promotion/promoted/library.json \
|
||||
../../output/library.json \
|
||||
--family flanged_hub_adapter \
|
||||
--features base_flange,hollow_sleeve,counterbore
|
||||
```
|
||||
@@ -88,8 +87,10 @@ required.
|
||||
family without publishing any teacher dimensions.
|
||||
- Exact source paths, hashes, dimensions, coordinates, and face references are
|
||||
permitted in private case JSON and forbidden in the published library.
|
||||
- Keep input/output as a human-visible staging area and induction corpus. Never
|
||||
use it directly during creation, modification, or reconstruction.
|
||||
- Keep `input/` and `runs/` as a local-only induction corpus. Never use them
|
||||
directly during ordinary creation, modification, or reconstruction.
|
||||
- Commit only the verified runtime library in `output/`; never commit source
|
||||
STEP files, extracted evidence, review drafts, reports, or rebuilt parts.
|
||||
- A semantic candidate is not a trusted design method until repeated,
|
||||
independently sourced cases satisfy the promotion policy.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
Case JSON is private evidence used only during induction. It may contain exact
|
||||
parameters, but the inducer never copies those fields into published experience.
|
||||
Store source STEP files in `workspace/teacher/inbox` and generated private
|
||||
evidence in `workspace/teacher/evidence`.
|
||||
Store source STEP files in `input/` and generated private evidence in
|
||||
`runs/evidence/`.
|
||||
|
||||
Do not pass either folder or a case JSON to cad-router or a CAD backend.
|
||||
Creation, modification, and reconstruction may consume only the promoted public
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# LLM semantic review contract
|
||||
|
||||
Read the sanitized `work/review/semantic-batch.json`, not raw STEP geometry.
|
||||
Read the sanitized `runs/review/semantic-batch.json`, not raw STEP geometry.
|
||||
Maintain stable proposal identifiers when an existing candidate expresses the
|
||||
same method.
|
||||
|
||||
Write `work/review/experience-draft.json` with this shape:
|
||||
Write `runs/review/experience-draft.json` with this shape:
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -618,17 +618,15 @@ def plugin_root() -> Path:
|
||||
|
||||
|
||||
def default_library_path() -> Path:
|
||||
return (
|
||||
plugin_root()
|
||||
/ "workspace"
|
||||
/ "promotion"
|
||||
/ "promoted"
|
||||
/ "library.json"
|
||||
)
|
||||
return plugin_root() / "output" / "library.json"
|
||||
|
||||
|
||||
def parser_root() -> Path:
|
||||
return plugin_root() / "workspace" / "teacher"
|
||||
def input_root() -> Path:
|
||||
return plugin_root() / "input"
|
||||
|
||||
|
||||
def runs_root() -> Path:
|
||||
return plugin_root() / "runs"
|
||||
|
||||
|
||||
def step_files(root: Path) -> list[Path]:
|
||||
@@ -684,7 +682,7 @@ def extract_folder(input_dir: Path, output_dir: Path) -> dict[str, Any]:
|
||||
|
||||
|
||||
def default_review_dir() -> Path:
|
||||
return plugin_root() / "workspace" / "promotion" / "candidates"
|
||||
return runs_root() / "review"
|
||||
|
||||
|
||||
def prepare_semantic_batch(
|
||||
@@ -1088,15 +1086,15 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
extract_folder_parser = subparsers.add_parser("extract-folder")
|
||||
extract_folder_parser.add_argument(
|
||||
"--input", type=Path, default=parser_root() / "inbox"
|
||||
"--input", type=Path, default=input_root()
|
||||
)
|
||||
extract_folder_parser.add_argument(
|
||||
"--output", type=Path, default=parser_root() / "evidence"
|
||||
"--output", type=Path, default=runs_root() / "evidence"
|
||||
)
|
||||
|
||||
prepare_parser = subparsers.add_parser("prepare")
|
||||
prepare_parser.add_argument(
|
||||
"--input", type=Path, default=parser_root() / "evidence"
|
||||
"--input", type=Path, default=runs_root() / "evidence"
|
||||
)
|
||||
prepare_parser.add_argument(
|
||||
"--library", type=Path, default=default_library_path()
|
||||
@@ -1110,7 +1108,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
publish_parser = subparsers.add_parser("publish")
|
||||
publish_parser.add_argument("--draft", type=Path, required=True)
|
||||
publish_parser.add_argument(
|
||||
"--input", type=Path, default=parser_root() / "evidence"
|
||||
"--input", type=Path, default=runs_root() / "evidence"
|
||||
)
|
||||
publish_parser.add_argument(
|
||||
"--library", type=Path, default=default_library_path()
|
||||
@@ -1125,7 +1123,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
help="LLM-authored proposal draft. Without this, publishing is blocked.",
|
||||
)
|
||||
distill_parser.add_argument(
|
||||
"--input", type=Path, default=parser_root() / "evidence"
|
||||
"--input", type=Path, default=runs_root() / "evidence"
|
||||
)
|
||||
distill_parser.add_argument(
|
||||
"--library", type=Path, default=default_library_path()
|
||||
|
||||
@@ -107,6 +107,15 @@ def make_case(index: int) -> dict:
|
||||
|
||||
|
||||
class CadExperienceTest(unittest.TestCase):
|
||||
def test_default_data_paths_use_shallow_local_layout(self):
|
||||
pipeline_root = Path(__file__).parents[1].resolve()
|
||||
self.assertEqual(pipeline_root / "input", MODULE.input_root())
|
||||
self.assertEqual(pipeline_root / "runs", MODULE.runs_root())
|
||||
self.assertEqual(
|
||||
pipeline_root / "output" / "library.json",
|
||||
MODULE.default_library_path(),
|
||||
)
|
||||
|
||||
def reviewed_proposal(self) -> dict:
|
||||
return {
|
||||
"id": "constraint.flanged_hub_adapter.shared_axis",
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# Distillation Workspace
|
||||
|
||||
This directory is the runtime boundary for uploaded STEP reconstruction and
|
||||
experience distillation.
|
||||
|
||||
## Where to put target STEP files
|
||||
|
||||
Place STEP or STP files to be reconstructed in:
|
||||
|
||||
```text
|
||||
teacher/inbox/
|
||||
```
|
||||
|
||||
Use unique, stable filenames. Batch inputs are intentionally ignored by Git so
|
||||
large private corpora do not inflate the repository.
|
||||
|
||||
## Where each stage is stored
|
||||
|
||||
| Stage | Directory | Contents |
|
||||
| --- | --- | --- |
|
||||
| Source input | `teacher/inbox/` | Original target STEP/STP files. |
|
||||
| Extracted evidence | `teacher/evidence/` | Private geometry facts extracted from each source. |
|
||||
| Agent A input | `reconstruction/inbox/` | Sanitized evidence packets and reconstruction requests. |
|
||||
| Agent A result | `reconstruction/designir/` | Executable `*.designir.json` models. |
|
||||
| Independent rebuild | `reconstruction/output/` | STEP rebuilt without teacher-file access; SimpleCAD jobs may also emit model JSON. |
|
||||
| Agent B input | `acceptance/inbox/` | Acceptance manifests linking teacher, DesignIR, rebuild, and edit contract. |
|
||||
| Acceptance result | `acceptance/reports/` | Geometry, topology, semantic, and parameter-perturbation reports. |
|
||||
| Failed/unsupported | `quarantine/` | Unsupported vocabulary, invalid cases, and failure clusters. |
|
||||
| Experience candidates | `promotion/candidates/` | Generalized methods proposed from validated cases. |
|
||||
| Replay gate | `promotion/replay_validated/` | Methods repeated successfully across independent cases. |
|
||||
| Final distilled result | `promotion/promoted/library.json` | Only deterministic, promoted experience consumed by CAD Router. |
|
||||
|
||||
## Data flow
|
||||
|
||||
```text
|
||||
teacher/inbox/*.step
|
||||
-> teacher/evidence/
|
||||
-> reconstruction/inbox/
|
||||
-> reconstruction/designir/
|
||||
-> reconstruction/output/*.step
|
||||
-> acceptance/inbox/
|
||||
-> acceptance/reports/
|
||||
-> promotion/candidates/
|
||||
-> promotion/replay_validated/
|
||||
-> promotion/promoted/library.json
|
||||
```
|
||||
|
||||
Agent A cannot read `teacher/inbox/`. Agent B may read the teacher STEP and the
|
||||
rebuilt result, but neither agent can directly publish experience. Promotion is
|
||||
performed only by the deterministic policy gate.
|
||||
|
||||
The `.gitkeep` files preserve this layout in Git. Runtime STEP files, evidence,
|
||||
rebuilds, and reports remain local by default.
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,494 +0,0 @@
|
||||
{
|
||||
"schema_version": "2.0",
|
||||
"library_kind": "generalized_cad_experience",
|
||||
"generated_at": "2026-07-23T08:16:40+00:00",
|
||||
"induction_mode": "llm_proposals_with_deterministic_evidence_verification",
|
||||
"status": "ready",
|
||||
"policy": {
|
||||
"instance_parameters_allowed": false,
|
||||
"absolute_coordinates_allowed": false,
|
||||
"single_case_promotion_allowed": false,
|
||||
"llm_semantic_review_required": true,
|
||||
"draft_evidence_verified": true,
|
||||
"router_consumable": true,
|
||||
"minimum_support": 20,
|
||||
"minimum_confidence": 0.8
|
||||
},
|
||||
"corpus_summary": {
|
||||
"accepted_case_count": 2,
|
||||
"duplicate_case_count": 0,
|
||||
"rejected_case_count": 0,
|
||||
"family_count": 11
|
||||
},
|
||||
"experience_summary": {
|
||||
"llm_proposal_count": 4,
|
||||
"promoted_experience_count": 0,
|
||||
"candidate_experience_count": 4,
|
||||
"by_kind": [],
|
||||
"by_scope": [],
|
||||
"candidate_by_kind": [
|
||||
{
|
||||
"kind": "constraint",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"kind": "feature_motif",
|
||||
"count": 2
|
||||
},
|
||||
{
|
||||
"kind": "validation_rule",
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"experiences": [
|
||||
{
|
||||
"id": "constraint.rotational_part.shared_dominant_axis",
|
||||
"kind": "constraint",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"rotational_body"
|
||||
],
|
||||
"relations": [
|
||||
"dominant_axis_alignment"
|
||||
]
|
||||
},
|
||||
"guidance": "Preserve the dominant axis as the organizing datum for rotational feature roles.",
|
||||
"semantic_rationale": "The datum transfers because axis alignment is independent of the individual component dimensions.",
|
||||
"support": 2,
|
||||
"confidence": 1.0,
|
||||
"check": "Confirm that rotational feature roles remain aligned to the same organizing datum.",
|
||||
"promotion_state": "candidate",
|
||||
"required_support": 20,
|
||||
"remaining_support": 18,
|
||||
"required_confidence": 0.8,
|
||||
"consumer_policy": "visible_for_review_but_not_available_to_cad_router"
|
||||
},
|
||||
{
|
||||
"id": "motif.rotational_part.coaxial_core_with_center_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"circular_equal_radius_pattern"
|
||||
],
|
||||
"relations": [
|
||||
"shared_passage_axis"
|
||||
]
|
||||
},
|
||||
"guidance": "Treat the rotational body, coaxial cylindrical stack, and central passage as one shared-axis core.",
|
||||
"semantic_rationale": "The relationship transfers because the participating roles describe axis organization rather than a particular size.",
|
||||
"support": 2,
|
||||
"confidence": 1.0,
|
||||
"check": "Confirm that the rotational body, stacked cylindrical roles, and central passage retain their intended common axis.",
|
||||
"promotion_state": "candidate",
|
||||
"required_support": 20,
|
||||
"remaining_support": 18,
|
||||
"required_confidence": 0.8,
|
||||
"consumer_policy": "visible_for_review_but_not_available_to_cad_router"
|
||||
},
|
||||
{
|
||||
"id": "motif.rotational_part.patterned_axial_mounting",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"repeated_axial_hole_pattern",
|
||||
"rotational_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 55,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.hollow_or_stepped_shaft.coaxial_cylindrical_stack+stepped_cylindrical_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"hollow_or_stepped_shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"stepped_cylindrical_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 46,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.hollow_or_stepped_shaft.rotational_body+coaxial_cylindrical_stack",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"hollow_or_stepped_shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"rotational_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 46,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.hollow_or_stepped_shaft.shaft_like_body+elongated_body",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"hollow_or_stepped_shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"elongated_body",
|
||||
"shaft_like_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 46,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.multi_axis_manifold.cylindrical_feature_network+multi_axis_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"multi_axis_manifold"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"cylindrical_feature_network",
|
||||
"multi_axis_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 55,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.multi_axis_manifold.planar_dominant_body+multi_level_planar_profile",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"multi_axis_manifold"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"multi_level_planar_profile",
|
||||
"planar_dominant_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 44,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_plate.cylindrical_feature_network+multi_axis_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_plate"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"cylindrical_feature_network",
|
||||
"multi_axis_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 76,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_plate.planar_dominant_body+multi_level_planar_profile",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_plate"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"multi_level_planar_profile",
|
||||
"planar_dominant_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 202,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_plate.repeated_axial_hole_pattern+circular_equal_radius_pattern",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_plate"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"circular_equal_radius_pattern",
|
||||
"repeated_axial_hole_pattern"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 66,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_prismatic_part.cylindrical_feature_network+multi_axis_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_prismatic_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"cylindrical_feature_network",
|
||||
"multi_axis_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 156,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_prismatic_part.planar_dominant_body+multi_level_planar_profile",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_prismatic_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"multi_level_planar_profile",
|
||||
"planar_dominant_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 323,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.patterned_prismatic_part.repeated_axial_hole_pattern+circular_equal_radius_pattern",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"patterned_prismatic_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"circular_equal_radius_pattern",
|
||||
"repeated_axial_hole_pattern"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 159,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.plate_or_bracket.planar_dominant_body+multi_level_planar_profile",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"plate_or_bracket"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"multi_level_planar_profile",
|
||||
"planar_dominant_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 35,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.prismatic_block.planar_dominant_body+multi_level_planar_profile",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"prismatic_block"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"multi_level_planar_profile",
|
||||
"planar_dominant_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 67,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.rotational_part.coaxial_cylindrical_stack+stepped_cylindrical_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"stepped_cylindrical_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 123,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.rotational_part.rotational_body+coaxial_cylindrical_stack",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"rotational_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 123,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.shaft.coaxial_cylindrical_stack+stepped_cylindrical_passage",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"stepped_cylindrical_passage"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 40,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.shaft.rotational_body+coaxial_cylindrical_stack",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"coaxial_cylindrical_stack",
|
||||
"rotational_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 40,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "motif.shaft.shaft_like_body+elongated_body",
|
||||
"kind": "feature_motif",
|
||||
"scope": [
|
||||
"shaft"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"elongated_body",
|
||||
"shaft_like_body"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Treat the participating feature roles as one coordinated composition rather than unrelated primitives.",
|
||||
"semantic_rationale": "The composition recurs across independent dimensional variants in the same family.",
|
||||
"support": 40,
|
||||
"confidence": 1.0
|
||||
},
|
||||
{
|
||||
"id": "reconstruction.flanged_rotational_part.primary",
|
||||
"kind": "reconstruction_grammar",
|
||||
"scope": [
|
||||
"flanged_rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"circular_equal_radius_pattern",
|
||||
"coaxial_cylindrical_stack",
|
||||
"cylindrical_feature_network",
|
||||
"multi_level_planar_profile",
|
||||
"repeated_axial_hole_pattern",
|
||||
"rotational_body",
|
||||
"stepped_cylindrical_passage"
|
||||
],
|
||||
"relations": [
|
||||
"repeated_radius_group"
|
||||
]
|
||||
},
|
||||
"guidance": "Represent repeated axial holes as a symmetric mounting pattern tied to the rotational body.",
|
||||
"semantic_rationale": "The motif remains useful across variants because it captures repeated functional placement around a rotational form.",
|
||||
"support": 2,
|
||||
"confidence": 1.0,
|
||||
"check": "Confirm that repeated axial holes remain grouped consistently around the rotational body.",
|
||||
"promotion_state": "candidate",
|
||||
"required_support": 20,
|
||||
"remaining_support": 18,
|
||||
"required_confidence": 0.8,
|
||||
"consumer_policy": "visible_for_review_but_not_available_to_cad_router"
|
||||
},
|
||||
{
|
||||
"id": "validation.rotational_part.axis_and_pattern_consistency",
|
||||
"kind": "validation_rule",
|
||||
"scope": [
|
||||
"rotational_part"
|
||||
],
|
||||
"when": {
|
||||
"features": [
|
||||
"central_passage",
|
||||
"repeated_axial_hole_pattern"
|
||||
],
|
||||
"relations": []
|
||||
},
|
||||
"guidance": "Validate both the shared rotational axis and the grouped repeated-hole relationship before handoff.",
|
||||
"semantic_rationale": "These checks protect transferable intent without relying on instance geometry.",
|
||||
"support": 2,
|
||||
"confidence": 1.0,
|
||||
"check": "Confirm shared-axis alignment and repeated-hole grouping before treating the model as ready.",
|
||||
"promotion_state": "candidate",
|
||||
"required_support": 20,
|
||||
"remaining_support": 18,
|
||||
"required_confidence": 0.8,
|
||||
"consumer_policy": "visible_for_review_but_not_available_to_cad_router"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -58,7 +58,7 @@ Write `cad-task.json` beside the task artifacts with this minimum shape:
|
||||
],
|
||||
"parameters": {},
|
||||
"experience": {
|
||||
"library": "../../../designir-pipeline/workspace/promotion/promoted/library.json",
|
||||
"library": "../../../designir-pipeline/output/library.json",
|
||||
"context_kind": "generalized_cad_experience_query",
|
||||
"methods_applied": []
|
||||
},
|
||||
@@ -74,10 +74,10 @@ have a sibling `*.designir.json` that owns its coordinate system, datums,
|
||||
parameters, expressions, features, constraints, edit interface, and validation
|
||||
contract. See `designir-2.0.md`.
|
||||
|
||||
For an uploaded STEP, keep teacher geometry in the protected ingestion and
|
||||
acceptance workspace. The reconstruction task contains private evidence,
|
||||
DesignIR, backend source, and rebuilt STEP but no teacher STEP or imported
|
||||
B-Rep.
|
||||
For an uploaded STEP, keep teacher geometry in `designir-pipeline/input/` and
|
||||
all private evidence, DesignIR candidates, rebuilds, and acceptance reports in
|
||||
`designir-pipeline/runs/`. The reconstruction task receives evidence but no
|
||||
teacher STEP or imported B-Rep.
|
||||
|
||||
## Backend adapter requirements
|
||||
|
||||
|
||||
@@ -241,15 +241,13 @@ def default_experience_library() -> Path | None:
|
||||
configured = os.environ.get("CAD_EXPERIENCE_LIBRARY", "").strip()
|
||||
if configured:
|
||||
return Path(configured).expanduser()
|
||||
workspace_candidate = (
|
||||
published_candidate = (
|
||||
SKILL_ROOT.parents[2]
|
||||
/ "designir-pipeline"
|
||||
/ "workspace"
|
||||
/ "promotion"
|
||||
/ "promoted"
|
||||
/ "output"
|
||||
/ "library.json"
|
||||
)
|
||||
return workspace_candidate if workspace_candidate.is_file() else None
|
||||
return published_candidate if published_candidate.is_file() else None
|
||||
|
||||
|
||||
def classify_edit_context(
|
||||
@@ -265,20 +263,18 @@ def classify_edit_context(
|
||||
(
|
||||
SKILL_ROOT.parents[2]
|
||||
/ "designir-pipeline"
|
||||
/ "workspace"
|
||||
/ "teacher"
|
||||
/ "input"
|
||||
).resolve(),
|
||||
(
|
||||
SKILL_ROOT.parents[2]
|
||||
/ "designir-pipeline"
|
||||
/ "workspace"
|
||||
/ "acceptance"
|
||||
/ "runs"
|
||||
).resolve(),
|
||||
]
|
||||
if any(source == root or root in source.parents for root in protected_roots):
|
||||
raise ValueError(
|
||||
"cad-router reconstruction cannot read the teacher or acceptance "
|
||||
"vault; pass the ingestion job reference or an editable DesignIR"
|
||||
"cad-router reconstruction cannot read distillation input or run "
|
||||
"artifacts; pass an editable DesignIR outside the private pipeline"
|
||||
)
|
||||
suffix = source.suffix.lower() if source else ""
|
||||
text = request.lower()
|
||||
|
||||
@@ -363,12 +363,10 @@ class CadRouterTests(unittest.TestCase):
|
||||
teacher_source = (
|
||||
Path(__file__).resolve().parents[5]
|
||||
/ "designir-pipeline"
|
||||
/ "workspace"
|
||||
/ "teacher"
|
||||
/ "inbox"
|
||||
/ "input"
|
||||
/ "part.step"
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "cannot read the teacher"):
|
||||
with self.assertRaisesRegex(ValueError, "cannot read distillation input"):
|
||||
route_module.route(
|
||||
self.parse(
|
||||
"修改这个零件",
|
||||
@@ -377,6 +375,23 @@ class CadRouterTests(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_private_run_artifact_is_rejected_as_edit_source(self) -> None:
|
||||
run_source = (
|
||||
Path(__file__).resolve().parents[5]
|
||||
/ "designir-pipeline"
|
||||
/ "runs"
|
||||
/ "designir"
|
||||
/ "part.designir.json"
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "cannot read distillation input"):
|
||||
route_module.route(
|
||||
self.parse(
|
||||
"修改这个零件",
|
||||
"--edit-source",
|
||||
str(run_source),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user