입력·결과 타입, 단위와 오류
Type과 unit은 연결 가능한 값을 판단하고 잘못된 계산을 실행 전에 막기 위해 사용합니다. 예를 들어 길이 24 m는 길이 input에 연결할 수 있지만 힘 24 kN으로 자동 해석하지 않습니다. 같은 열 이름을 가진 표라도 field type이나 단위가 다르면 호환되는 표가 아닙니다.
Component API와 resolver의 현재 경계
px.setting(...)은 현재 public API이며 선언 schema는 component-declared-settings@1이 소유합니다. 현재 V1 @px.component는 companion descriptor metadata만 등록하며 installed declaration, executor나 renderer를 생성하지 않습니다. settings=로 붙인 px.Settings subclass의 field는 그 descriptor의 settings가 됩니다. production Flow reader는 installed Component target을 read-only unsupported로 열고 exact target·raw settings와 연결 사용처에서 유도한 일부 port만 보존합니다.
아래 Component editor·MCP·resolver diagnostic은 admitted target에 적용할 contract 의미입니다. 현재 production의 서드파티 Component install admission과 activation은 exact ProjectScope isolation과 execution-trust closure가 모두 닫힐 때까지 차단하며, diagnostic action이 그 차단을 우회하지 않습니다. 정확한 경계는 Component container V2와 서드파티 Node UI를 따릅니다.
V1 승인 bounds
다음 값은 RFC-003 승인과 함께 고정한 V1 상한입니다. 상한을 넘는 값이나 descriptor는 일부만 materialize하지 않고 진단과 함께 전체를 거부합니다.
| bound | 값 | 측정 기준 |
|---|---|---|
decimal.precisionMax | 38 | 부호와 decimal point를 제외한 전체 digit 수 |
decimal.scaleMin | 0 | decimal point 오른쪽 digit 수의 최솟값 |
decimal.scaleMax | 18 | decimal point 오른쪽 digit 수의 최댓값 |
semanticKey.maxLength | 128 | Unicode character 수 |
string.maxByteLength | 1048576 | UTF-8 byte 수(1 MiB) |
list.maxItems | 100000 | list item 수 |
table.maxRows | 100000 | table row 수 |
record.maxFields | 512 | record field descriptor 수 |
compositeDepth.max | 32 | root composite를 1로 세는 record·list·table nesting depth |
Decimal precision 38은 IEEE decimal128과 일반적인 DECIMAL(38,s) column에 맞습니다. 100,000 row는 structural hazard table과 load-case table에 필요한 여유를 남깁니다. Composite depth 32는 공격 방어와 실제 authoring을 모두 만족합니다.
V1 승인 unit registry
V1은 **UCUM 2.2 (2024-06-17)**을 pin합니다. 이 release는 UCUM 공식 specification이 날짜와 version을 함께 식별하고, 구현자가 사용할 ucum-essence.xml release artifact를 제공하는 최신 고정 specification이므로 선택했습니다. 전체 UCUM vocabulary를 노출하지 않고 다음 32개 case-sensitive canonical code만 허용합니다.
| engineering category | canonical code subset |
|---|---|
| dimensionless | 1, %, [ppm] |
| length | mm, cm, m, km, [in_i], [ft_i] |
| mass | mg, g, kg, t |
| time | ms, s, min, h |
| angle | rad, deg |
| force | N, kN, MN |
| stress/pressure | Pa, kPa, MPa, GPa, N/mm2 |
| moment | N.m, kN.m |
| density | kg/m3 |
| acceleration | m/s2 |
| temperature | K |
Derived force와 pressure 정의에 필요한 kg, m, s, N, Pa는 이 subset 안에 포함되어 있습니다. Moment는 owner가 승인한 kN.m sibling을 열며 canonical unit은 N.m로 유지합니다. MN.m는 승인되지 않았습니다. Density, acceleration, temperature는 owner가 지정한 canonical code 하나만 열며, 승인되지 않은 sibling code를 암묵적으로 추가하지 않습니다.
각 code의 canonical unit에 대한 conversion factor는 exponent 표기 없는 canonical decimal string으로 저장합니다. Multiplicative conversion은 {scale}을, affine conversion은 {scale, offset}을 사용하며 affine의 scale과 offset은 둘 다 canonical decimal string입니다. Conversion 중에는 rounding하지 않습니다. 결과가 선언된 decimal precision 38을 넘으면 값을 자르거나 반올림하지 않고 diagnostic을 반환합니다. V1 subset에는 non-zero offset이 필요한 unit pair가 없지만 affine wire form은 닫혀 있으며, fixture는 offset: "0"인 worked example로 두 member가 항상 존재함을 검증합니다.
승인 subset과 reader evolution 경계
실행 가능한 unit은 machine profile의 unit.canonicalCodeSubset 32개와 정확히 일치합니다. Direct schema, Component V2 input/result/setting admission과 Run input은 같은 case-sensitive 코드를 검사하며 M, pa 같은 미승인 값은 거부합니다. 화면용 임의 문구는 executable unit이 아니며, 필요하면 별도로 승인한 presentation role로 정의해야 합니다.
새 unit 또는 closed type kind는 versioned profile과 RFC-003 후속 결정이 필요합니다. 기존 reader가 모르는 값을 받기 전에 다음 소유 경계를 올려야 합니다.
- Package: 해당 package kind의
required_contract_version을 올립니다. Safe container 검사 다음, content/declaration 해석 전에 지원 범위를 확인합니다. 초과 시 typedContractTooNew { required, supported }를 반환하며 공개 응답은 기존PX_SCHEMA_UNSUPPORTED_VERSION의actualVersion/supportedVersion으로 분기합니다. 낮은 requirement를 거짓 선언한 unknown unit/type은 content admission에서 거부됩니다. - Runtime/binding wire: A1의 core contract 지원 range/handshake가 transport peer를 먼저 검사합니다. 새 vocabulary를 기존 지원 range에 슬쩍 추가해서는 안 됩니다.
- Standalone document: 문서
schemaVersion과 schema identity를 새 reader 세대로 올립니다. package나 handshake 없이 여는 reader는 document version 경계에서 거부합니다.
componentContractVersion은 특정 Component의 계약 revision이며 전역 UCUM subset을 확장하는 권한이 아닙니다. 현재 subset 교정은 새 code/kind를 도입하지 않아 버전을 올리지 않으며 별도의 custom unit registry도 만들지 않습니다.
V1 승인 diagnostic params contract
params는 아래에 적힌 key만 허용하는 closed object입니다. string은 locale-independent token, semantic key, ref, digest 또는 canonical decimal string이고 integer는 JSON integer입니다. 표의 key는 ascending order이며, 없는 key를 추가하거나 적힌 key를 생략하면 해당 code의 Diagnostic이 유효하지 않습니다.
| code | 허용 params (key:type) |
|---|---|
PX_SCHEMA_UNSUPPORTED_VERSION | actualVersion:string, supportedVersion:string |
PX_SCHEMA_UNKNOWN_FIELD | field:string |
PX_KEY_INVALID | key:string |
PX_KEY_DUPLICATE | key:string |
PX_REPORT_CONNECTION_NOT_FOUND | connectionKey:string |
PX_REPORT_FLOW_REVISION_NOT_FOUND | revisionRef:string |
PX_REPORT_MAPPING_SOURCE_NOT_FOUND | sourceKey:string |
PX_REPORT_MAPPING_TARGET_NOT_FOUND | targetKey:string |
PX_REPORT_MAPPING_CONFLICT | mappingTarget:string |
PX_REPORT_MAPPING_INCOMPATIBLE | sourceKind:string, targetKind:string |
PX_REPORT_TABLE_ROW_KEY_INVALID | reason:string, rowKey:string |
PX_REPORT_BATCH_REQUIRED | caseCount:integer |
PX_OUTPUT_EXISTS | outputName:string |
PX_AMBIGUOUS_TARGET | candidateCount:integer |
PX_TARGET_NOT_FOUND | targetKey:string |
PX_PACKAGE_NOT_INSTALLED | packageKey:string |
PX_PACKAGE_VERSION_MISMATCH | expectedVersion:string, installedVersion:string |
PX_PACKAGE_CATALOG_UNAVAILABLE | packageKey:string |
PX_PACKAGE_ACCESS_DENIED | packageKey:string |
PX_FUNCTION_NOT_FOUND | functionKey:string |
PX_FUNCTION_VERSION_MISMATCH | actualVersion:string, expectedVersion:string |
PX_COMPONENT_NOT_FOUND | componentKey:string |
PX_COMPONENT_CONTRACT_MISMATCH | actualDigest:string, expectedDigest:string |
PX_COMPONENT_UNRESOLVED | componentKey:string |
PX_PUBLIC_MODULE_INVALID | moduleName:string, reason:string, symbolName:string |
PX_DEPENDENCY_RESOLUTION_FAILED | packageKey:string, requestedRange:string |
PX_REQUIRED_INPUT_UNBOUND | portKey:string |
PX_PORT_NOT_FOUND | portKey:string |
PX_PORT_DIRECTION_MISMATCH | actualDirection:string, expectedDirection:string |
PX_TYPE_INCOMPATIBLE | sourceKind:string, targetKind:string |
PX_UNIT_INCOMPATIBLE | sourceUnit:string, targetUnit:string |
PX_CARDINALITY_AMBIGUOUS | observedCardinality:string |
PX_FORMULA_REFERENCE_NOT_FOUND | referenceKey:string |
PX_FORMULA_OPERATOR_UNSUPPORTED | operator:string |
PX_FORMULA_SHAPE_INCOMPATIBLE | actualShape:string, expectedShape:string |
PX_FORMULA_DOMAIN_ERROR | operator:string |
PX_FORMULA_COMPLEXITY_LIMIT | actual:integer, limit:integer |
PX_SOLVER_CONFIGURATION_INVALID | reason:string, settingKey:string |
PX_SOLVER_DID_NOT_CONVERGE | iterationLimit:integer |
PX_FLOW_CYCLE | nodeCount:integer |
PX_GROUP_INVALID | groupKey:string, reason:string |
PX_PLAN_EXPIRED | planRef:string |
PX_PLAN_MISMATCH | actualPlanDigest:string, expectedPlanDigest:string |
PX_GENERATION_STALE | actualGeneration:integer, expectedGeneration:integer |
PX_MERGE_CONFLICT | conflictCount:integer |
PX_SOURCE_EDIT_NOT_SAFE | reason:string |
PX_TARGET_NOT_PORTABLE | targetKind:string |
PX_PERMISSION_DENIED | requiredPermission:string |
PX_CAPABILITY_DENIED | capability:string |
PX_RESOURCE_LIMIT | actual:string, limit:string, resource:string |
PX_FUNCTION_FAILED | functionKey:string |
PX_COMPONENT_FAILED | componentKey:string |
PX_RESULT_NOT_FOUND | resultKey:string |
PX_RESULT_STALE | resultRevisionRef:string, sourceRevisionRef:string |
PX_EFFECT_INDETERMINATE | effectRef:string |
PX_DOCUMENT_LEGACY_FORMAT | detectedFormat:string |
PX_DOCUMENT_MALFORMED | 없음 |
PX_RUNTIME_UNREACHABLE | 없음 |
PX_RUNTIME_INCOMPATIBLE | actualVersion:string, supportedVersion:string |
PX_RUNTIME_DISCONNECTED | 없음 |
PX_BASE_REF_MISMATCH | actualHeadRef:string, expectedBaseRef:string |
PX_HEAD_ALREADY_EXISTS | actualGeneration:integer |
PX_PLAN_NOT_FOUND | planRef:string |
PX_FUNCTION_USAGE_STALE | 없음 |
PX_FUNCTION_BASE_TARGET_MISMATCH | baseTargetDigest:string, changeTargetDigest:string |
PX_FUNCTION_DRAFT_INVALID | reason:string |
PX_REQUEST_SHAPE_INVALID | member:string, reason:string |
PX_SOURCE_UNREADABLE | reason:string |
PX_RUN_STATE_CONFLICT | reason:string |
PX_SUBFLOW_DEPENDENCY_NOT_INSTALLED | flowKey:string |
PX_EXECUTION_INFRASTRUCTURE_FAILED | reason:string, stage:string |
PX_EXECUTION_INFRASTRUCTURE_FAILED는 사용자 함수 예외나 supervisor 연결 끊김이 아닌 실행 기반 실패입니다. 현재 Runtime이 생성하는 stage / reason 조합은 다음과 같습니다.
material/readFailed,invalidMaterialworkerStart/sandboxRejected,startFailedworkerResponse/invalidResponse,missingDiagnostic,noResponseresultCommit/writeFailed
code와 params로 분기하며 원시 OS 경로·저장소 메시지·worker 출력은 params에 넣지 않습니다. path는 실패 위치를 설명하고 retryable은 해당 실행 시도의 재시도 가능성입니다. 없는 Function·Component·외부 Subflow는 기존 진단 코드를 사용합니다. 새 코드를 받는 SDK는 같은 공개 registry를 포함해야 하므로 SDK와 bundled Runtime을 함께 갱신합니다. 71개 registry의 Core/SDK 호환성 버전은 1.1.0입니다. 이전 1.0.0 Client는 최초 handshake에서 기존 PX_RUNTIME_INCOMPATIBLE로 거부되며 UPDATE_APPLICATION을 안내합니다. 이 버전은 native binding과 Runtime 호출의 호환성 버전이며 저장 파일의 schemaVersion이나 기존 revision bytes를 변경하지 않습니다. 기존 저장 Run에 진단이 없는 경우는 그대로 읽으며 사후에 원인을 만들어 넣지 않습니다.
PX_FUNCTION_DRAFT_INVALID.params.reason은 policyNotExecutable, capabilityNotExecutable, dependencyNotExecutable, emptySource, entrySymbolInvalid, declaredVersionInvalid, timeoutInvalid, outputNotRequired, capabilityNetworkInvalid, dependencyPinInvalid 중 하나입니다. 중복 port·secret·dependency key는 각 key를 보존하는 PX_KEY_DUPLICATE를 사용하고, draft schema version 불일치는 PX_SCHEMA_UNSUPPORTED_VERSION을 사용합니다.
PX_REQUEST_SHAPE_INVALID.params.member는 요청 member 이름이고, params.reason은 runtime 요청에서는 memberSetUnexpected, memberTypeInvalid, memberValueInvalid 중 하나입니다. SDK descriptor 등록에서는 authoring-profile의 공개 분기에 따라 member="annotation"에 missingAnnotation 또는 unsupportedAnnotation, member="metadata"에 invalidMetadata를 사용합니다. SDK descriptor 진단의 path는 빈 문자열이며, runtime 요청의 path는 그 member의 JSON Pointer입니다. Key 자체가 문법 밖이면 PX_KEY_INVALID를, 중복이면 PX_KEY_DUPLICATE를 사용합니다.
PX_SOURCE_UNREADABLE.params.reason은 notFound, notPermitted, notReadable, notWritable 중 하나입니다. 호출자가 지정한 local 파일 경로에만 사용하며, 경로 문자열은 params에 넣지 않고 path가 그 요청 member를 가리킵니다.
PX_RUN_STATE_CONFLICT.params.reason은 transitionNotPermitted, runStateMoved, commandBodyConflict, batchAlreadySubmitted, projectionConflict, completionStale 중 하나입니다. 여섯 경우 모두 durable Run·Batch 상태가 요청이 가정한 상태와 다르다는 하나의 사실이며, 조치도 하나입니다 -- 다시 읽고 다시 요청합니다.
외부 Subflow가 이 Project의 설치 closure에서 resolve되지 않을 때는 두 code를 구분해서 씁니다. 그 Flow key를 publish하는 release가 하나도 설치되어 있지 않으면 PX_SUBFLOW_DEPENDENCY_NOT_INSTALLED를 쓰고 params.flowKey에 그 Flow key를 담습니다 -- 조치는 그 Flow를 publish하는 package를 설치하는 것입니다. Flow key는 설치되어 있고 요청이 지정한 exact target·revision만 없으면 PX_TARGET_NOT_FOUND를 씁니다 -- 조치는 설치된 target을 지정하는 것입니다. path는 어느 member가 문제인지만 가리키며 branch 기준이 아닙니다: client가 분기하는 것은 code와 params뿐입니다.
이 세 code는 2026-09-03 supervisor refusal 경계 결정과 함께 열렸습니다. 그 결정 이후 supervisor가 도달할 수 있는 모든 business 실패는 RFC-003 schema-valid Diagnostic을 가진 ResponseEnvelope 안에 남습니다. free-form prose나 {"detail": ...} 객체는 diagnostics 원소가 될 수 없습니다. 저장 레코드·내부 불변식 위반만 봉투 밖에서 {"outcome":"refusedWithoutFixedDiagnostic","reason":"invariantViolation","detail":<display-only>} 로 답하며, 그 detail은 비규범 표시 전용 문자열이라 어떤 client도 parsing하거나 분기하지 않습니다.
Canonical params-digest preimage은 key를 ascending order로 정렬한 뒤 RFC 8785 JCS를 적용한 bytes입니다. 이 preimage 정의는 RFC-002와 공동 소유하며 RFC-002의 정의와 항상 byte-for-byte 동일해야 합니다. Key 정렬 또는 JCS 규칙을 독립적으로 바꾸지 않습니다.
현재 SDK 개발자는 target input의 일반 Python parameter annotation과 px.Results annotated field에 type을 한 번 선언합니다. px.input(...), px.result(...)와 px.setting(...)은 그 선언부에 description·unit·required를 더하는 current facade의 metadata marker이고, px.field(...)만 contract_only인 계획 문법으로 남아 현재 public facade에 없습니다. Flow public port의 unit·description·constraint는 flow.input(...)과 flow.result(...)가 소유합니다. V1 Component companion descriptor의 port shape는 Python annotation에서 유도합니다. PXFLOW Studio는 materialize된 Flow와 Node port 계약을 읽고, Report Workbench는 같은 계약으로 authored value와 public input/result의 호환성을 확인합니다. 후속 admitted Component의 host projection과 MCP resolver도 같은 TypeDescriptor를 사용해야 하지만, 현재 installed Component editor나 MCP activation 경로가 있다는 뜻은 아닙니다.
지원하는 입력·결과 타입
값의 크기와 생김새에 맞는 type을 선택합니다. 숫자 하나는 scalar, 이름 있는 여러 값은 record, 같은 record의 여러 행은 table, PDF와 큰 결과 파일은 artifact를 사용합니다. Public port는 다음 kind만 사용합니다.
boolean · int64 · float64 · decimal · string · enum
date · timestamp · duration · record · list · table
binary · artifact · evidence · calculation_tracerecord는 ordered field descriptor와 조건부rowKeyField를 가집니다.list는 item type을 가집니다.table은 row record와 ordered field key를 가진 하나의 typed value입니다. table input 하나는 target을 한 번 실행합니다.enum은 stable key 목록과 label projection을 분리합니다.- file, image와 PDF는 path string이 아니라
artifact/binaryreference입니다. calculation_trace는 Function, Component 또는 Flow가 반환하는 수식·대입·solver·검토 근거의 immutable structured result입니다. arbitrary log, HTML이나 Python source가 아닙니다.- unrestricted
any와 unknown component fallback은 금지합니다.
Report의 여러 행을 List<T> 또는 Table<Record> public input에 연결하면 collection 하나로 ordinary Flow Run 한 번을 실행합니다. Scalar public input에 여러 행을 각각 전달하려면 explicit Batch Run을 선택하고 case 수와 result merge를 먼저 검토합니다.
Exact TypeDescriptor shape
{ "kind": "float64" }{ "kind": "record", "recordKey": "load_case" }{ "kind": "enum", "values": ["s355", "s460"] }{ "kind": "list", "items": { "kind": "float64" } }{
"kind": "table",
"row": { "kind": "record", "recordKey": "load_case" }
}{ "kind": "calculation_trace" }recordKey는 자신을 소유한 FunctionDescriptor, ComponentDescriptor 또는 Flow interface의 typeDefinitions closure에서 exact definition을 resolve합니다. Record definition의 조건부 rowKeyField는 해당 Record를 Table row로 쓸 때 사용할 exact field를 가리키며 그 field는 required·non-null string 또는 int64여야 합니다. enum values는 중복 없는 semantic key 오름차순이며 화면 label은 type 의미에 포함하지 않습니다. list.items와 table.row는 다시 TypeDescriptor입니다.
Direct Flow의 소유 closure는 같은 immutable Flow revision의 optional top-level typeDefinitions.records[]입니다. 각 record definition은 recordKey, ordered fields[]와 optional rowKeyField를 갖고, 각 field는 fieldKey, type, required, nullable을 모두 저장합니다. Closure가 있으면 Flow interface에서 도달하는 record descriptor가 모두 resolve되어야 합니다. 기존 V1 document가 closure를 생략한 경우에는 그 revision을 계속 읽되 record Run value를 object 경계까지만 검증합니다. 현재 Run value나 다른 revision의 moving definition에서 field를 역추론하지 않습니다.
calculation_trace 값은 수식, 대입, solve·iteration·check 구조와 실행 provenance를 담습니다. Report에 표시할 때는 authored value로 복사하지 않고 result mapping이 immutable Result snapshot을 읽습니다.
숫자와 시간
int64는 type context 안에서 leading zero 없는 base-10 string으로 직렬화합니다.float64는 finite JSON number만 허용하고-0을0으로 정규화합니다.decimal은 canonical decimal string입니다. 문법은 선택적 leading-,0이거나 leading zero 없는 digit string인 integer part, 그리고 선택적.뒤에 trailing zero 없는 digit string인 fraction part입니다. fraction이 없는-0은 거부합니다. 따라서01,1.0,.5,1.,+1,-0은 모두 canonical이 아니며PX_TYPE_INCOMPATIBLE로 거부합니다. 한 값에 표기가 하나뿐이므로 canonical bytes와 digest를 바인딩 간에 그대로 비교할 수 있습니다.- 값의 표기는 값 자체만 나타냅니다. 유효자릿수나 재료 산포처럼 "이 값이 얼마나 잘 알려져 있는가"를 담는 별도 field는 V1 계약에 없습니다. 그런 값은 측정이나 확률 해석에서 나오며 결정론적 계산의 결과가 아니므로, 계산 프로그램 사이의 중립 교환 형식인 V1의 질문이 아닙니다. 약속하는 문장과 담는 field는 함께 존재하거나 함께 존재하지 않습니다. 한쪽만 남기는 것이 계약을 깨뜨립니다.
NaN,Infinity, locale 숫자와 표시용 comma는 numeric typed value에 저장하지 않습니다.- timestamp는 UTC RFC 3339, date는 ISO 8601 date, duration은 canonical ISO 8601 duration입니다.
unit
Unit은 화면에 붙이는 문자열이 아니라 값의 차원과 변환 규칙입니다. 숫자형 공학 값에는 canonical unit을 선언하고, 단위가 없는 비율에는 1을 사용합니다.
- UCUM 2.2 (2024-06-17)의 위 32개 case-sensitive canonical code만 사용합니다.
- dimensionless는
1입니다. - generic conversion은 multiplicative 또는 affine
{scale, offset}만 지원합니다. - nonlinear/logarithmic conversion은 명시적 Function이어야 합니다.
- type이 맞아도 dimension이 다르면 연결할 수 없습니다.
- compatible unit conversion은 validator가 plan에 표시하고 Runtime provenance에 남깁니다.
canonical unit discipline
저장·계산·digest되는 값은 항상 해당 물리량의 canonical unit입니다. 변환은 ingress normalisation과 presentation/export egress에서만 일어나고 그 밖의 어디에서도 일어나지 않습니다. 표시 단위를 바꾸는 일이 저장된 값을 다시 쓰는 일이 되어서는 안 됩니다.
canonical system은 coherent SI입니다.
| category | canonical unit |
|---|---|
| dimensionless | 1 |
| length | m |
| mass | kg |
| time | s |
| angle | rad |
| force | N |
| stress/pressure | Pa |
| moment | N.m |
| density | kg/m3 |
| acceleration | m/s2 |
| temperature | K |
- ingress: 사용자가 제출한 값은
MeasuredDecimal이며 아직 canonical이 아닙니다.normalise()가 이를 canonical unit으로 변환해CanonicalQuantity를 만듭니다. 이미 canonical인 값도 같은 문을 지나고, 그때 변환은 exact identity입니다. - storage/calculation:
CanonicalQuantity만 저장·계산·digest에 들어갑니다. private field와 canonical unit을 검사하는 단 하나의 constructor를 가지므로, 이 type을 들고 있다는 사실 자체가 ingress normalisation을 통과했다는 증거입니다. 새 call site가 잊을 수 있는 검사가 아닙니다. - egress:
CanonicalQuantity::present_in(target)은CanonicalQuantity가 아니라PresentationQuantity를 반환합니다. 이 type은 public constructor가 없고Deserialize도 없으며 저장 가능한 값으로 가는 경로가 없습니다. 따라서 표시 변환 결과는 저장될 수 없습니다. - 사용자 재제출: 사용자가
3.28 [ft_i]처럼 보고 있는 값을 다시 입력하는 것은 별개의 일이며 계속 동작합니다.into_resubmitted_input()이 그 값을 새 ingress input으로 돌려주고, 다른 모든 입력과 똑같이normalise()를 지나 새 canonical value가 됩니다. 금지되는 것은 표시 변환의 조용한 write-back뿐입니다. - moment는
N.m와kN.m를 허용하고 canonical unit은N.m입니다. 두 방향 변환은 exact이며1 kN.m = 1000 N.m입니다.MN.m는 승인되지 않았습니다. Density, acceleration, temperature에는 owner가 지정한 canonical code만 있습니다. 특히Cel과[degF]는 affine unit이므로, temperature에 추가하려면 각 code의 승인을 받은 뒤genericConversionForms와affineMembers가 이미 선언한{scale, offset}경로를 registry conversion planner에 연결해야 합니다. 현재는 그 경로를 사용하는 registry code가 없습니다.
Diagnostic envelope
입력이나 연결을 사용할 수 없을 때는 화면마다 다른 문자열을 반환하지 않습니다. 모든 제품이 같은 diagnostic code와 오류 위치를 받고, 각 화면이 이를 사용자 언어로 설명합니다. 사용자는 무엇이 잘못됐는지와 다음에 할 일을 보고, 개발자는 같은 diagnosticId로 실행 기록을 찾을 수 있습니다.
{
"code": "PX_UNIT_INCOMPATIBLE",
"path": "/flow/nodes/resistance_check/inputBindings/span",
"severity": "error",
"retryable": false,
"params": {
"sourceUnit": "kN",
"targetUnit": "m"
},
"suggestedAction": "SELECT_COMPATIBLE_PORT",
"diagnosticId": "opaque-correlation"
}path는 RFC 6901 JSON Pointer이며 root는 빈 문자열""입니다.code,path,severity,retryable,params,suggestedAction은 항상 포함합니다. 추가 parameter가 없으면params는 빈 object이고,severity는error,warning,info중 하나입니다.params는 locale-independent structured values입니다.- 사용자 문구는 UI가
code + params로 지역화합니다. diagnosticId는 server correlation이며 Local/offline 진단에서는 생략할 수 있습니다.- 여러 진단은 severity(
error,warning,info)의 선언 순서 뒤에 path, code, canonical params digest를 각각 ascending으로 적용해 정렬합니다. - 이 object가 HTTP, MCP, SDK와 UI가 공유하는 canonical Diagnostic wire shape입니다. Localized
message,recoveryActions[]또는 surface별 자유 형식 field를 같은 object에 추가하지 않습니다. 복구 동작 하나는suggestedAction, 추가 선택지는 별도 typedcandidates또는nextActionsresponse field로 제공합니다.
v1 core stable code registry
다음 표는 type·unit·numeric·Flow·Report mapping·Runtime core가 소유한 v1 stable code 집합입니다. PX_ prefix는 core가 예약하지만, core 밖의 업무 영역은 자신의 계약 문서에서 같은 envelope와 명명 규칙으로 code를 소유합니다.
| 영역 code 소유 문서 | decision record |
|---|---|
organization-access-and-policy.md | RFC-006 |
report-output-and-external-delivery.md | RFC-008 |
../integrations/mcp-and-llm.md | RFC-010 |
publication-and-embed-delivery.md | RFC-011 |
이 네 문서 밖의 사용자·API 문서는 새 PX_ code를 만들지 않고 아래 core 표의 code를 그대로 인용합니다.
Component diagnostic은 설치 명령이 아닙니다
아래 package·Component row는 resolver가 반환할 stable code와 target semantics를 고정합니다. INSTALL_PACKAGE, INSTALL_PACKAGE_VERSION, SELECT_COMPONENT, REVIEW_COMPONENT_UPDATE와 RESOLVE_COMPONENT는 typed suggestedAction 식별자이며, 현재 production 서드파티 Component 설치·활성화 UI/CLI/MCP를 승인하지 않습니다. 현재 reader는 exact target·raw settings와 usage-derived partial ports를 read-only로 보존합니다.
| code | 의미 | 기본 suggestedAction |
|---|---|---|
PX_SCHEMA_UNSUPPORTED_VERSION | 지원하지 않는 production schema | OPEN_READ_ONLY |
PX_SCHEMA_UNKNOWN_FIELD | unknown core field | REMOVE_UNKNOWN_FIELD |
PX_KEY_INVALID | semantic key grammar 위반 | RENAME_KEY |
PX_KEY_DUPLICATE | scope 안 key 중복 | RENAME_KEY |
PX_REPORT_CONNECTION_NOT_FOUND | exact connectionKey를 current Report revision에서 찾을 수 없음 | SELECT_REPORT_CONNECTION |
PX_REPORT_FLOW_REVISION_NOT_FOUND | Report connection이 고정한 exact Flow revisionRef를 resolve할 수 없음 | CHOOSE_FLOW_REVISION |
PX_REPORT_MAPPING_SOURCE_NOT_FOUND | input mapping의 Report block·field·table source를 찾을 수 없음 | SELECT_REPORT_SOURCE |
PX_REPORT_MAPPING_TARGET_NOT_FOUND | result mapping의 Report block·slot·table destination을 찾을 수 없음 | SELECT_REPORT_DESTINATION |
PX_REPORT_MAPPING_CONFLICT | 같은 Flow input 또는 Report result 위치를 둘 이상의 active mapping이 소유함 | REVIEW_REPORT_MAPPING |
PX_REPORT_MAPPING_INCOMPATIBLE | Report source/destination과 Flow public port의 type·unit·shape가 맞지 않음 | SELECT_COMPATIBLE_PORT |
PX_REPORT_TABLE_ROW_KEY_INVALID | selected Table의 row key가 없거나 nullable·중복 상태임 | SELECT_ROW_KEY |
PX_REPORT_BATCH_REQUIRED | 여러 scalar case를 scalar input에 각각 실행하도록 사용자가 선택함 | CREATE_BATCH_RUN |
PX_OUTPUT_EXISTS | 생성할 파일과 다른 기존 파일이 있음 | CHOOSE_OUTPUT |
PX_AMBIGUOUS_TARGET | 검색 후보가 둘 이상 | SELECT_TARGET |
PX_TARGET_NOT_FOUND | full scope와 semantic key로 지정한 exact target을 찾을 수 없음 | SELECT_EXACT_TARGET |
PX_PACKAGE_NOT_INSTALLED | exact SDK package가 target Project의 admitted installed closure에 없음 | INSTALL_PACKAGE |
PX_PACKAGE_VERSION_MISMATCH | Project closure의 package version이 exact ref와 다름 | INSTALL_PACKAGE_VERSION |
PX_PACKAGE_CATALOG_UNAVAILABLE | SDK package catalog를 조회할 수 없어 exact release를 resolve하지 못함 | RETRY_PACKAGE_CATALOG |
PX_PACKAGE_ACCESS_DENIED | SDK package 또는 release를 읽거나 설치할 권한이 없음 | REQUEST_PACKAGE_ACCESS |
PX_FUNCTION_NOT_FOUND | pinned Function을 resolve할 수 없음 | INSTALL_FUNCTION |
PX_FUNCTION_VERSION_MISMATCH | Node contract가 바뀜 | REVIEW_FUNCTION_UPDATE |
PX_COMPONENT_NOT_FOUND | exact package/project owner에 componentKey가 없음 | SELECT_COMPONENT |
PX_COMPONENT_CONTRACT_MISMATCH | generic/successor V2에서 resolved installed declaration이 saved exact ComponentRef와 충돌하거나 raw settings·usage-derived partial ports를 현재 declaration에 안전하게 admit할 수 없음; generic persisted full/last-verified snapshot 비교를 뜻하지 않음. current V1 Engineering Paper legacy setting 검증은 기존 domain codec 경계임 | REVIEW_COMPONENT_UPDATE |
PX_COMPONENT_UNRESOLVED | installed Component의 exact release, descriptor 또는 executable source를 완전히 resolve하지 못함 | RESOLVE_COMPONENT |
PX_PUBLIC_MODULE_INVALID | public Python import·symbol·.pyi가 descriptor와 불일치 | FIX_PUBLIC_API |
PX_DEPENDENCY_RESOLUTION_FAILED | 요청 range와 channel trust policy를 만족하는 compatible package release를 고정할 수 없음 | SELECT_COMPATIBLE_VERSION |
PX_REQUIRED_INPUT_UNBOUND | required input 연결 없음 | CONNECT_INPUT |
PX_PORT_NOT_FOUND | exact port key 없음 | SELECT_COMPATIBLE_PORT |
PX_PORT_DIRECTION_MISMATCH | input/result 방향 오류 | SELECT_COMPATIBLE_PORT |
PX_TYPE_INCOMPATIBLE | closed type/shape 불일치 | SELECT_COMPATIBLE_PORT |
PX_UNIT_INCOMPATIBLE | unit dimension 불일치 | SELECT_COMPATIBLE_PORT |
PX_CARDINALITY_AMBIGUOUS | direct typed Run request의 scalar·list·table shape를 하나로 확정할 수 없음 | FIX_RUN_REQUEST_SHAPE |
PX_FORMULA_REFERENCE_NOT_FOUND | FormulaExpression의 exact value reference를 찾을 수 없음 | SELECT_FORMULA_REFERENCE |
PX_FORMULA_OPERATOR_UNSUPPORTED | 지원하지 않는 formula operator 또는 operand shape | REWRITE_FORMULA |
PX_FORMULA_SHAPE_INCOMPATIBLE | scalar·vector·matrix shape가 연산과 맞지 않음 | FIX_FORMULA_SHAPE |
PX_FORMULA_DOMAIN_ERROR | core math operator 또는 다른 formula operation의 수학적 정의역을 벗어남 | FIX_FORMULA_DOMAIN |
PX_FORMULA_COMPLEXITY_LIMIT | FormulaExpression의 node 수 또는 depth가 배포 한도를 초과함 | SIMPLIFY_FORMULA |
PX_SOLVER_CONFIGURATION_INVALID | method, unknown, initial value, tolerance 또는 branch 설정이 유효하지 않음 | REVIEW_SOLVER_SETTINGS |
PX_SOLVER_DID_NOT_CONVERGE | 허용한 iteration 안에서 수렴하지 않음 | REVIEW_CONVERGENCE |
PX_FLOW_CYCLE | Flow connection cycle | REMOVE_CYCLE |
PX_GROUP_INVALID | Group member가 둘 미만이거나, member 중복·다중 Group membership 또는 nested Group을 요청함 | FIX_GROUP |
PX_PLAN_EXPIRED | 검토한 Plan의 유효 시간이 끝났거나 pinned precondition이 더 이상 유효하지 않음 | REFRESH_AND_REPLAN |
PX_PLAN_MISMATCH | Apply의 plan digest, target, expected generation 또는 command body가 검토한 Plan과 다름 | REFRESH_AND_REPLAN |
PX_GENERATION_STALE | expected generation 불일치 | REFRESH_AND_REPLAN |
PX_MERGE_CONFLICT | current revision과 proposed command가 같은 semantic path를 서로 다르게 변경함 | REVIEW_CONFLICTS |
PX_SOURCE_EDIT_NOT_SAFE | SDK-linked 변경을 기존 source에 손실 없이 표현하거나 rematerialize parity를 증명할 수 없음 | OPEN_SOURCE_OR_CREATE_NATIVE_COPY |
PX_TARGET_NOT_PORTABLE | session-only target이 저장·내보내기에 남음 | ATTACH_DEPENDENCY |
PX_PERMISSION_DENIED | capability 없음 | REQUEST_ACCESS |
PX_CAPABILITY_DENIED | execution target의 runtime capability 거부 | REVIEW_CAPABILITY |
PX_RESOURCE_LIMIT | CPU/memory/time/result-size budget 초과 | REDUCE_WORKLOAD |
PX_FUNCTION_FAILED | sanitized Function target execution failure | OPEN_DIAGNOSTIC |
PX_COMPONENT_FAILED | sanitized Component execution failure | OPEN_DIAGNOSTIC |
PX_RESULT_NOT_FOUND | requested result 없음 | SELECT_RESULT |
PX_RESULT_STALE | source/revision과 result가 다름 | RUN_AGAIN |
PX_EFFECT_INDETERMINATE | 외부 effect 결과 확정 불가 | RECONCILE_EFFECT |
PX_DOCUMENT_LEGACY_FORMAT | 이전 PXFLOW 포맷으로 작성된 document | OPEN_READ_ONLY |
PX_DOCUMENT_MALFORMED | decode 불가능한 document | CHOOSE_ANOTHER_FILE |
PX_RUNTIME_UNREACHABLE | 실행 중인 runtime 프로세스가 없음 | START_RUNTIME |
PX_RUNTIME_INCOMPATIBLE | runtime이 호환되지 않는 release | UPDATE_APPLICATION |
PX_RUNTIME_DISCONNECTED | 요청 중 runtime 연결이 끊김 | RUN_AGAIN |
PX_BASE_REF_MISMATCH | 변경이 base로 지정한 ref(Flow·Report는 revisionRef, Function은 versionRef)가 더 이상 head가 아님 | REFRESH_AND_REPLAN |
PX_HEAD_ALREADY_EXISTS | 첫 저장인데 해당 key의 head가 이미 존재함 | REFRESH_AND_REPLAN |
PX_PLAN_NOT_FOUND | Apply가 지정한 단기 Plan이 없거나 이미 정리됨 | REFRESH_AND_REPLAN |
PX_FUNCTION_USAGE_STALE | Function 변경 Plan 이후 연결된 Flow/Report usage가 달라짐 | REFRESH_AND_REPLAN |
PX_FUNCTION_BASE_TARGET_MISMATCH | Function 변경 command의 base target과 변경 target이 서로 다른 Function을 가리킴 | REFRESH_AND_REPLAN |
PX_FUNCTION_DRAFT_INVALID | Function draft shape가 저장 가능한 규칙을 충족하지 않음 | REVIEW_FUNCTION_UPDATE |
PX_REQUEST_SHAPE_INVALID | 요청의 member 집합·JSON kind·값이 해당 operation이 받는 것이 아님 | FIX_RUN_REQUEST_SHAPE |
PX_SOURCE_UNREADABLE | 호출자가 지정한 local 파일을 읽거나 쓸 수 없음 | CHOOSE_ANOTHER_FILE |
PX_RUN_STATE_CONFLICT | durable Run·Batch 상태가 요청이 가정한 상태와 다름 | REFRESH_AND_REPLAN |
PX_SUBFLOW_DEPENDENCY_NOT_INSTALLED | 외부 Subflow가 가리키는 Flow를 publish하는 release가 이 Project에 설치되어 있지 않음 | INSTALL_PACKAGE |
PX_EXECUTION_INFRASTRUCTURE_FAILED | 실행 자료 저장소·worker 시작/응답·결과 저장 실패 | OPEN_DIAGNOSTIC |
SDK package별 Function/Component error는 package namespace를 붙인 uppercase code를 사용할 수 있습니다. core PX_ prefix는 예약되어 있습니다.
surface mapping
| surface | 업무 오류 표현 |
|---|---|
| Rust/Native | Diagnostic[] |
| Python SDK | PxValidationError(diagnostics); expected target 오류는 typed result diagnostic |
| HTTP | operation에 도달한 요청은 application/json ResponseEnvelope + schema-valid diagnostics; protocol 실패는 RFC 9457 application/problem+json이며 diagnostics 없음 |
| MCP | 업무 결과는 isError: false + schema-valid structuredContent; router failure만 JSON-RPC error |
| Studio/Report | 같은 code를 지역화하고 suggested action 버튼 제공 |
Stack trace, host path, secret, internal UUID mapping과 다른 tenant candidate는 public diagnostic에 넣지 않습니다.
호환성 기준은 Diagnostic.code와 params입니다. 각 surface가 제공하는 예외·오류 클래스는 같은 사실을 그 언어의 관용구로 전달하는 편의 계층이며, 호환성 단위가 아닙니다. 하나의 code가 여러 클래스로 갈 수 있고 한 클래스가 여러 code를 받을 수 있으므로, 분기해야 하는 호출자는 클래스가 아니라 code를 읽습니다. 클래스는 잡는 데 쓰고, code로 무엇을 할지 정합니다.
Diagnostic vocabulary와 binding failure
V1 suggestedAction은 현재 profile의 50 distinct member로 닫히며 추가는 versioned follow-up contract가 필요합니다. REPORT_UNREADABLE_FILE과 RESTORE_FROM_BACKUP은 명시적으로 거절한 non-member literal이고 dedicated declined-candidate field 밖에서는 vocabulary citation이 아닙니다.
Decode failure는 WASM에서 sentence message를 가진 Error, Python에서 ValueError이며 둘 다 full Diagnostic JCS bytes를 diagnostic member에 보존합니다. Generated TypeScript surface는 PxflowDecodeFailure extends Error { readonly diagnostic: Uint8Array }를 공개하고 caller는 caught unknown을 narrow합니다. RFC-003 correctness gate는 stdlib-Python contract reimplementation으로 accepted diagnostic ordering fixture를 Rust core와 독립 비교합니다.
Python SDK 도메인 실패 분기
공개 SDK에서는 from pipelinexlab import px로 가져온 px.Error를 잡습니다. diagnostics의 code/params와 refusal_reason이 공개 분기이며 메시지와 detail은 표시 전용입니다.
| 실패 소유 경계 | 공개 분기 |
|---|---|
| Function/Component descriptor 등록 | authoring-profile의 PX_REQUEST_SHAPE_INVALID member/reason 또는 PX_KEY_DUPLICATE key |
| Report 열기: 문서 없음 | PX_TARGET_NOT_FOUND, params.targetKey=<reportKey> |
| Report 열기: revision 없음 | PX_TARGET_NOT_FOUND, params.targetKey=<revisionRef> |
| 저장된 Report connection의 Flow revision 없음 | PX_REPORT_FLOW_REVISION_NOT_FOUND, params.revisionRef=<revisionRef> |
| Report 또는 연결된 Flow의 반환 bytes가 요청한 revision digest와 불일치 | 빈 diagnostics와 refusal_reason="invariantViolation" |
| Runtime이 거부한 Flow/Report/Run/Batch/package operation | Runtime의 registry Diagnostic을 보존; out-of-envelope 거부는 닫힌 refusal_reason을 보존 |
| worker 평가 실패 | 기존 registry Diagnostic 유지; generic fallback은 PX_DOCUMENT_MALFORMED |
| 사용자 Function/Component 본문 exception | PX_FUNCTION_FAILED / PX_COMPONENT_FAILED; exception detail과 stack은 표시 전용 |
Report key와 revision ref는 요청한 식별자 그대로 params에 보존됩니다. 누락을 invariant로 분류하거나 메시지에서 code를 추출하지 않습니다. 아직 개별 분류가 없는 SDK-local Flow/Report authoring, Client/session precondition, packaging/preview와 protocol-shape 예외는 px.Error로 잡을 수 있지만 코드별 복구 분기를 보장하지 않습니다. 이 표는 모든 private exception의 코드 배정을 주장하지 않으며 built-in TypeError는 일반 Python 호출 오류로 유지합니다.