A-SW Hub / Repositories
Local Gitea · READ ONLY
← 저장소 Repositories
REPOSITORY

metafarmers/fruit-robot-validation Private

[참조 MVP] 적과·적심 로봇 통합검증 — 인지·접근·작업·복귀 시나리오와 제품 기준선의 재현성을 확인하는 참조 검증 자산입니다.

https://git.agrithing.ai/metafarmers/fruit-robot-validation.git
4 commits
COMMIT DETAIL

feat: 적과·적심 로봇 통합검증 구체 MVP 구현

기관 승인 및 자동 품질검사를 통과한 구체 MVP 0.2.0 병합 Co-authored-by: meta-dev <[email protected]>

meta-dev <[email protected]> · 2026. 8. 3. 오후 3:13:18
7b9733dd2152bcf91d75d962a04edc701ab44f9b
8 changed files +89 −12 parent f93f075
modified README.md +7−1 View file
@@ -11,6 +11,12 @@
11 11
12 12 인지·접근·작업·복귀 시나리오와 제품 기준선의 재현성을 확인하는 참조 검증 자산입니다.
13 13
14 + ## MVP 동작 범위
15 +
16 + - 필수 제품 시나리오 커버리지 검사
17 + - 실측값과 허용기준 자동 판정
18 + - 누락·실패 시 제품 검증 차단
19 +
14 20 ## 실행
15 21
16 22 ```bash
@@ -18,4 +24,4 @@ python run.py examples/input.json
18 24 python -m unittest discover -s tests -v
19 25 ```
20 26
21 실제 기관 구현은 `contracts/component.interface.json`의 저장소 식별자와 제품 기준선 연결 규칙을 유지하면서 교체할 수 있습니다.
27 + 정상 입력은 `examples/input.json`, 차단·안전 경로는 `examples/failure-input.json`으로 재현합니다. 실제 기관 구현은 `contracts/component.interface.json`의 저장소 식별자와 제품 기준선 연결 규칙을 유지하면서 교체할 수 있습니다.
modified asw_component/component.py +18−5 View file
@@ -1,9 +1,22 @@
1 1 from __future__ import annotations
2 2
3 + REQUIRED = set(["FRUIT-THIN-01","FRUIT-PINCH-01","FRUIT-SAFE-01"])
4 +
3 5
4 6 def execute(payload: dict) -> dict:
5 scenarios = payload.get("scenarios", [])
6 results = [{"id": item["id"], "passed": bool(item.get("passed"))} for item in scenarios]
7 passed = sum(item["passed"] for item in results)
8 accepted = bool(results) and passed == len(results)
9 return {"component": "metafarmers/fruit-robot-validation", "accepted": accepted, "status": "READY" if accepted else "BLOCKED", "verdict": "PASS" if accepted else "FAIL", "passed": passed, "total": len(results), "results": results}
7 + results = []
8 + seen = set()
9 + for scenario in payload.get("scenarios", []):
10 + scenario_id = str(scenario.get("id", ""))
11 + seen.add(scenario_id)
12 + actual, limit = float(scenario.get("actual", 0)), float(scenario.get("limit", 0))
13 + operator = scenario.get("operator")
14 + passed = actual <= limit if operator == "lte" else actual >= limit if operator == "gte" else False
15 + results.append({"id": scenario_id, "actual": actual, "limit": limit, "operator": operator, "passed": passed})
16 + missing = sorted(REQUIRED - seen)
17 + passed_count = sum(item["passed"] for item in results)
18 + accepted = bool(results) and not missing and passed_count == len(results)
19 + return {"component": "metafarmers/fruit-robot-validation", "accepted": accepted,
20 + "status": "VERIFIED" if accepted else "BLOCKED", "target": "validation",
21 + "verdict": "PASS" if accepted else "FAIL", "passed": passed_count,
22 + "total": len(results), "missingRequired": missing, "results": results}
modified contracts/component.interface.json +22−1 View file
@@ -5,7 +5,13 @@
5 5 "required": [
6 6 "component",
7 7 "accepted",
8 "status"
8 + "status",
9 + "target",
10 + "verdict",
11 + "passed",
12 + "total",
13 + "missingRequired",
14 + "results"
9 15 ],
10 16 "properties": {
11 17 "component": {
@@ -19,6 +25,21 @@
19 25 },
20 26 "target": {
21 27 "const": "validation"
28 + },
29 + "verdict": {
30 + "type": "string"
31 + },
32 + "passed": {
33 + "type": "integer"
34 + },
35 + "total": {
36 + "type": "integer"
37 + },
38 + "missingRequired": {
39 + "type": "array"
40 + },
41 + "results": {
42 + "type": "array"
22 43 }
23 44 }
24 45 }
added examples/failure-input.json +16−0 View file
@@ -0,0 +1,16 @@
1 + {
2 + "scenarios": [
3 + {
4 + "id": "FRUIT-THIN-01",
5 + "actual": 8.4,
6 + "limit": 10,
7 + "operator": "lte"
8 + },
9 + {
10 + "id": "FRUIT-PINCH-01",
11 + "actual": 0.93,
12 + "limit": 0.9,
13 + "operator": "gte"
14 + }
15 + ]
16 + }
modified examples/input.json +12−3 View file
@@ -2,15 +2,24 @@
2 2 "scenarios": [
3 3 {
4 4 "id": "FRUIT-THIN-01",
5 "passed": true
5 + "actual": 8.4,
6 + "limit": 10,
7 + "operator": "lte",
8 + "unit": "s"
6 9 },
7 10 {
8 11 "id": "FRUIT-PINCH-01",
9 "passed": true
12 + "actual": 0.93,
13 + "limit": 0.9,
14 + "operator": "gte",
15 + "unit": "success-rate"
10 16 },
11 17 {
12 18 "id": "FRUIT-SAFE-01",
13 "passed": true
19 + "actual": 0.21,
20 + "limit": 0.3,
21 + "operator": "lte",
22 + "unit": "s"
14 23 }
15 24 ]
16 25 }
modified pyproject.toml +1−1 View file
@@ -1,5 +1,5 @@
1 1 [project]
2 2 name = "fruit-robot-validation"
3 version = "0.1.0"
3 + version = "0.2.0"
4 4 description = "인지·접근·작업·복귀 시나리오와 제품 기준선의 재현성을 확인하는 참조 검증 자산입니다."
5 5 requires-python = ">=3.11"
modified release/manifest.json +1−1 View file
@@ -4,7 +4,7 @@
4 4 "displayName": "적과·적심 로봇 통합검증",
5 5 "owner": "주식회사 메타파머스",
6 6 "implementationAuthor": "주식회사 비아 (연동 검증용 참조 구현)",
7 "version": "0.1.0-mvp",
7 + "version": "0.2.0-mvp",
8 8 "domain": "Validation",
9 9 "status": "REFERENCE_MVP",
10 10 "compatibility": {
modified tests/test_component.py +12−0 View file
@@ -12,6 +12,18 @@ class ComponentTest(unittest.TestCase):
12 12 result = execute(payload)
13 13 self.assertTrue(result["accepted"])
14 14 self.assertEqual(result["component"], "metafarmers/fruit-robot-validation")
15 + self.assertEqual(result["target"], "validation")
16 + self.assertEqual(result["verdict"], "PASS")
17 + self.assertEqual(result["passed"], 3)
18 + self.assertEqual(result["missingRequired"], [])
19 +
20 + def test_safety_or_failure_path(self):
21 + payload = json.loads((ROOT / "examples/failure-input.json").read_text(encoding="utf-8"))
22 + result = execute(payload)
23 + self.assertEqual(result["component"], "metafarmers/fruit-robot-validation")
24 + self.assertFalse(result["accepted"])
25 + self.assertEqual(result["verdict"], "FAIL")
26 + self.assertIn("FRUIT-SAFE-01", result["missingRequired"])
15 27
16 28 if __name__ == "__main__":
17 29 unittest.main()