51 KiB
Analysis semantics: competing designs and a bounded proposed contract
Codex-956atf /root/requirements_delta, 2026-09-10, finalized 2026-09-11. Design proposal for root synthesis and independent criticism, not a ratified decision, implementation, or release acceptance. Sole output of this assignment is this file. No production edits, Cargo or native execution. Read Gitea coordination through #81 before starting and through #101 on resuming; announced this work in #83. Coordinated neutral-definition identity and immutable import assumptions with /root/libraries_design; incorporated the paired critic's numeric serialization counterexample and library compatibility concern. Root retains build/native ownership.
The authoritative user objective and the delta evidence are recorded in PROJECT_GOAL.md and release-requirements-delta-20260910.md. This report examines the actual core at 8547b85 and its unchanged analysis-relevant predecessors. The current Constraint/MessageValue expressions remain prose; DataType/DataField units remain strings. This proposal must not reinterpret those existing records during migration.
On resuming, read the full replacement objective at C:/Users/User/.codex/attachments/a49d1780-25d5-4778-ad68-6140c60e4207/goal-objective.md (SHA-256 DD58F75C93D55FE16ED141A23D834898FB6EBC625AE7E7AE379DA552A8312435). Its explicit requirements for low-clutter notation, reduced cognitive load, human/AI editing and complete small/large model development through text strengthen the authoring gates in sections 3.4 and 7. This design update is not a fresh production audit of the concurrently changing checkout.
1. The decision and its evidence
The key question is whether a numerical value belongs directly to a modeled subject, to one explicit analysis case, or to a subject declaration plus case-specific assignment. A second question is how much mathematics the first release must execute. Neither question is settled by having a text field called expression.
Capella's official material identifies properties, expressions and dimensions and describes analysis through viewpoints. Its mass/cost/latency examples support useful architectural analysis without requiring behavioral simulation. Capella comparison, Capella features
SysML 2.0 separates calculation definitions/applications, Boolean constraints and quantity/unit concepts. Its calculation semantics include pure reusable computations; its quantity treatment distinguishes a quantity kind from a particular unit. Those distinctions inform this proposal; they do not make the proposed Studio language SysML-conformant. OMG language specification, §§7.8, 7.19, 7.20 and 9.8
For the temperature falsifier below, BIPM defines the Celsius/Kelvin numerical relationship with the exact offset 273.15 and distinguishes temperature values from intervals. The proposed affine algebra is a Studio design interpretation of that distinction. BIPM SI Brochure, ninth edition, temperature discussion
The implementation constraints are concrete:
model.rs:603–617,651contains current unit/expression metadata;parent_permits(validation.rs:92) permits DataFields only in data/item structures. A payload type default must not become a system property value accidentally.Project::layer_offollows an Element's layer or a Relation's source (model.rs:1803). There is no neutral modeling layer. New reusable definitions must not masquerade as OA or relax all existing same-layer checks.prepare_commandclones, applies a complete batch, finishes deletion handling, validates, then returns the candidate (session.rs:185). This is the mutation boundary to retain.visit_element_refscurrently visits live UUID references; expression text has no visited references (references.rs:17–152). Actual expression references require a typed visitor, not text search.- Transition closure follows references and selected ownership (
transitions.rs:447–606);inferred_kindhas a closed catalog. New property/case/check semantics will not transition automatically merely because they use SharedBody. - Historical review is a closed typed vocabulary (
semantic/types.rs:88–155). New live references and historical observations require different validation rules, as in existing source5–7 history.
Paths above are under crates/oa-core/src.
2. Alternatives and provisional ranking
Ratings below are engineering judgments to be falsified by examples and native tasks, not measurements.
| Architecture | Simple property/budget | Alternative assumptions | Meaning and automation | Main cost |
|---|---|---|---|---|
| A. Directly owned value/expression; no cases | Best initial simplicity. One property contains its value or derived expression. | Requires editing the one model state or copying declarations/projects. | Clear single-state meaning; weak support for simultaneous alternatives. | Adding cases later may reinterpret every property read. |
| B. Directly owned baseline value plus explicit override cases | Good initial simplicity; ordinary properties work without a case. | Case chooses a base and stores local overrides. Unchanged properties follow the base. | Viable if every resolved input reports its origin and inheritance rules are explicit. | Two value locations, inherited-change effects, override clearing versus unbound values, and derived-value lookup across scopes. An explicit UseBase(property) binding avoids implicit fallback but adds records/actions. |
| C. Case-owned values with optional subject annotations; no reusable property declarations | A case can be a compact typed worksheet. | Each case owns independent columns/values. | All inputs are explicit and isolated. | “The same system property” in two cases has no stable shared identity without another correspondence mechanism. |
| D. Subject property declarations plus complete explicit case bindings | One extra named case concept; no value is stored on the property declaration. Inline formulas suffice for small tasks. | The same declaration can have different, visibly separate bindings in nominal/degraded cases. No inheritance or fallback. | Stable property identity, explicit assumptions, one value location per case/property, simple pure evaluation. | More semantic records and source declarations; UI must make the common task one coherent action instead of several catalog detours. |
Provisional preference: D, because stable property identity and explicit assumptions support engineering studies and cross-project reuse without implementing override inheritance. This preference is conditional on the low-overhead workflows below. B is a credible competitor, not a straw man. If native comparison shows that engineers mostly enter context-independent facts and D forces repeated case creation or input copying, prefer B with explicit base provenance and a precisely defined override contract, or revisit a visible UseBase form. Do not add an invisible “default case” to rescue D; that would change the chosen semantics.
Reusable calculation definitions are orthogonal to A–D. A small budget must support an inline expression. Requiring a reusable function definition, parameter list and application before adding two durations would be unnecessary authoring overhead. “Make reusable” can be a later explicit transformation of a selected expression.
Numerical alternatives
| Domain | Exact decimal budgets and large integers | Degrees/radians and ordinary functions | Reproducibility / cost | Disposition |
|---|---|---|---|---|
| Q. Bounded exact rational scalar algebra | Exact within stated size limits; 0.1 + 0.2 == 0.3 and rational divisions are unambiguous. |
Cannot generally evaluate π-based conversion, sine, cosine, logarithms or irrational roots. Must report Unsupported. | Small, precise arithmetic contract; bounded big-integer implementation required. | Good first implementation slice, insufficient evidence for broad common-unit/calculation usability. |
| F. Finite binary64 throughout | Decimal rounding and large-integer loss require care. Existing i64 rules must stay independent. | Familiar engineering functions and approximate angular conversion are practical. | Must fix conversion, rounding, math function behavior and comparison policy; CPU/library differences need measured bounds. | Plausible simpler release choice if ordinary numerical breadth dominates exactness. |
| Q+F. Explicit exact and approximate domains | Exact calculations stay exact; approximation occurs at a visible domain boundary. | An implemented approximate domain handles angles and transcendental functions with explicit result labeling/policy. | More type/evaluation rules and two conformance suites. No implicit approximate-to-exact conversion. | Preferred target for further release design, conditional on a justified, independently verified approximate profile. |
This report formalizes Q as a bounded foundation. It does not claim that Q alone satisfies the user's complete calculations/quantities requirement. The approximate profile remains a consequential design/acceptance item, not a harmless future convenience. In particular, an everyday 30 deg → rad or sin(30 deg) request must either run under an implemented approximate domain or receive a precise Unsupported result. A decimal constant pretending to be exact π is unacceptable.
Before implementing F, compare a portable pinned Rust math implementation against platform intrinsics using reference values and documented error limits. Select rounding, supported function domains, signed-zero behavior, overflow/underflow and comparison semantics explicitly. Approximation labeling is not an error bound; a user-supplied engineering tolerance is not automatically a proof of numerical accuracy. Do not implement approximate equality by an undocumented global epsilon. That work is outside this exact first slice and must remain open in the release ledger.
3. Proposed model and low-overhead authoring
3.1 Meanings
An EngineeringProperty declares what scalar or finite scalar collection is associated with an existing semantic subject and its type. It stores no value/default. Its subject is an existing Element or Relation in the same layer, excluding analysis records themselves. Using an explicit typed subject reference supports an exchange's latency as well as a function's duration without pretending a Relation can be an Element parent.
An AnalysisCase names one set of input assumptions and derived bindings in one layer. It maps property identity to an expression or an explicit unbound value. A property read always means that property's binding in the named case. There is no lookup in another case, payload default, selected diagram, active UI state or external file. Case subject is optional explanatory focus, not an implicit namespace or lookup scope.
An AnalysisCheck is an identified, case-owned Boolean predicate. It may link an existing descriptive Constraint as its documented requirement. The old Constraint's prose remains prose; the new check supplies the formal assertion in an explicit case. Several checks/cases may reference the same documented Constraint. A check without that link still expresses a formal engineering constraint.
A neutral CalculationDefinition has stable typed parameters, a declared result and an optional pure expression body. A Boolean-valued reusable calculation can supply a predicate to a check. Definitions may call other definitions but cannot capture project properties, cases, UI selection, files, clocks or mutable external state.
3.2 Concrete Rust sketch
The names below are proposed, not existing public APIs. Closed Serde records and duplicate-key rejection follow current conventions.
// Proposal: three new Kind/SharedBody variants, using existing Element identity.
enum AnalysisSubject { Element(Id), Relation(Id) }
enum ScalarType {
Boolean,
Number, // Q1: exact rational
Quantity(DefinitionRef), // must resolve to a QuantityKind
}
enum AnalysisType { Scalar(ScalarType), List(ScalarType) } // no nested lists
// SharedBody additions:
EngineeringProperty {
subject: AnalysisSubject,
value_type: AnalysisType,
display_unit: Option<DefinitionRef>, // compatible quantity kind; no value/default
},
AnalysisCase {
subject: Option<AnalysisSubject>,
bindings: BTreeMap<Id, Option<Expr>>, // key is EngineeringProperty identity
},
AnalysisCheck { documented_constraint: Option<Id>, predicate: Option<Expr> },
// Project gets a separate neutral definition catalog, coordinated with libraries.
enum DefinitionRef {
Local(Id),
Imported { import: Id, package: PackageId, member: Id },
}
struct Parameter { id: ParameterId, name: String, value_type: AnalysisType }
struct CalculationDefinition {
parameters: Vec<Parameter>,
result: AnalysisType,
body: Option<Expr>,
}
struct Exact { numerator: CanonicalInteger, denominator: CanonicalPositiveInteger }
// Wire representation is canonical decimal strings, not JSON floating numbers.
struct Dimension([i16; 7]); // length, mass, time, current, temperature, amount, luminous intensity
enum QuantityAlgebra { Linear, Affine { difference_kind: DefinitionRef } }
struct QuantityKindDefinition { dimension: Dimension, algebra: QuantityAlgebra }
struct UnitDefinition {
kind: DefinitionRef,
scale: Exact, // strictly positive in Q1
offset: Exact, // zero for a Linear kind
symbol: String, // presentation; never identity
}
enum Expr {
Boolean(bool), Number(Exact),
Quantity { magnitude: Exact, unit: DefinitionRef },
Property(Id), Parameter(ParameterId), List(Vec<Expr>),
Unary { op: UnaryOp, operand: Box<Expr> },
Binary { op: BinaryOp, left: Box<Expr>, right: Box<Expr> },
If { condition: Box<Expr>, when_true: Box<Expr>, when_false: Box<Expr> },
Call { definition: DefinitionRef, arguments: BTreeMap<ParameterId, Expr> },
Sum { values: Box<Expr>, initial: Box<Expr> },
Power { base: Box<Expr>, exponent: i8 },
AsKind { kind: DefinitionRef, value: Box<Expr> },
}
EngineeringProperty and AnalysisCase are layer-root Elements. AnalysisCheck requires parent AnalysisCase. The subject relationship is explicit reference association, not an extra containment rule. Property ownership/attachment is therefore visible in the Properties/Analysis presentation even though it is not an Element child of its subject. If user testing instead requires the property to participate in semantic containment, revisit this choice explicitly; do not give parent two meanings.
display_unit is permitted only for a quantity scalar or quantity list and must have the property's resolved kind. It chooses result presentation, not input interpretation or a default value. A source literal retains its own magnitude/unit. Without a requested display unit, the wire result remains a canonical coordinate plus resolved kind; the UI must not invent a unit symbol. The Add value/budget forms can explicitly set this field from the visible unit choice.
Parameter IDs are scoped to the defining CalculationDefinition and remain stable through rename. They are not ordinary project Element references. A call's argument keys must exactly match the definition's parameter IDs. Wrong/missing/duplicate argument keys reject; an input whose value is not known is represented by a case binding set to None, not an invalid argument map. Empty calculation bodies/check predicates are admitted incomplete records with warnings.
3.3 Minimum GUI and source work
For one new property/value, the proposed minimum GUI operation is: select the modeled subject, choose Add analysis value, enter name/value/unit, and choose or visibly name the case. One final Create applies a batch creating the property, a new named case when needed, and its binding. The form states the case name and resulting records. Creating “Nominal” is explicit model creation, not implicit fallback. Existing cases are chosen by context, with alternatives visible. No separate global-catalog visit is required.
For a two-duration budget, one compact New budget form can show case name, two named input rows with subjects/units, the result expression and threshold. One Create reserves all new IDs and applies one reviewed batch: three properties, one case with three bindings and one check. A reusable definition is not mandatory. Subsequent editing shows nominal and alternative case values side by side or under an explicit case selector; the result always bears its case name. Outside an analysis workspace, a property inspector lists its case values with names rather than silently displaying one “current” value.
Local neutral definitions can make the source self-contained; library imports may supply the same definitions instead. Proposed syntax, not accepted by source7:
quantity_kind duration "Duration" {
dimension [0, 0, 1, 0, 0, 0, 0]; algebra Linear;
}
unit s "Second" { kind @duration; scale 1; offset 0; symbol "s"; }
unit ms "Millisecond" { kind @duration; scale 0.001; offset 0; symbol "ms"; }
The source cost for one property/value is two declarations, using those unit definitions:
oa_property receive_time "Receive time" { subject @receive; type Quantity(@duration); display_unit @ms; }
oa_analysis nominal "Nominal" { bindings { @receive_time = 750 [@ms]; } }
The two-case budget can remain concise without inventing a reusable function:
oa_property receive_time "Receive time" { subject @receive; type Quantity(@duration); }
oa_property dispatch_time "Dispatch time" { subject @dispatch; type Quantity(@duration); }
oa_property total_time "Total time" { subject @respond; type Quantity(@duration); display_unit @s; }
oa_analysis nominal "Nominal" {
bindings {
@receive_time = 750 [@ms];
@dispatch_time = 1 [@s];
@total_time = @receive_time + @dispatch_time;
}
}
oa_analysis degraded "Degraded radio" {
bindings {
@receive_time = 1250 [@ms];
@dispatch_time = 1 [@s];
@total_time = @receive_time + @dispatch_time;
}
}
oa_check nominal_budget "Nominal budget" {
parent @nominal; predicate @total_time <= 2 [@s];
}
oa_check degraded_budget "Degraded budget" {
parent @degraded; predicate @total_time <= 2 [@s];
}
Optional explicit reuse adds a neutral definition and changes a binding expression:
calculation combine "Combine durations" {
input a : Quantity(@duration);
input b : Quantity(@duration);
result Quantity(@duration);
expression $a + $b;
}
// In one case: @total_time = @combine(a: @receive_time, b: @dispatch_time);
Ordinary declaration UUID stabilization follows the existing source identity rule. The proposed authoring form extends optional initial IDs to calculation parameters: accepting a new parameter allocates its ID once, and the accepted source retains it, for example input a id "10000000-0000-4000-8000-000000000001" : Quantity(@duration);. This extension is a proposal, not existing source7 behavior. The short examples show initial authored text, not the more verbose stabilized file. Retaining established IDs is required for rename and history; deleting an ID is not a rename mechanism. Stabilization must be available through the shared source admission service without creating records in a GUI. Missing-ID diagnostics and the inserted IDs must be reviewable by a text-only client.
$name resolves only a parameter of the current definition. @name in value position resolves a case property; @name(...) resolves a calculation; [@name] resolves a unit. Imported qualified spelling is delegated to the library grammar. Duplicate binding keys reject. Names are parsed to stable IDs, and an accepted rename updates the relevant tokens. none is permitted as an entire binding/body/predicate hole, never as an arithmetic scalar. Parentheses, unary operators, multiply/divide, add/subtract, comparisons, &&, ||, and conditional expressions require explicit precedence in the normative extension; comparisons are non-associative, so chained comparisons reject. Quoted prose is never implicitly parsed as this expression language.
To test D against B, compare first-property creation, a two-input budget and a nominal/degraded change in both a small and a dense model. Proposed acceptance: D needs no additional page change and at most one additional context-choice action for the first case; editing an existing case needs no extra case-creation action. If D repeatedly requires recreating declarations or reentering unchanged inputs where B would show clear inheritance, its claimed simplicity is falsified. Record task completion/time and wrong-context errors, not just click counts.
3.4 Text-only development and cognitive load
The source examples are a minimum analysis fragment assuming existing subjects receive, dispatch and respond; they do not prove that an entire model can be authored through text. The acceptance fixture must include those OA/SA subjects and all other referenced records, local definitions or explicit supplied package imports, with no prerequisite GUI-created records. Adding a case, defining/reusing a calculation, declaring a quantity/unit, inspecting a missing input and correcting a constraint must all be possible from the published language and API alone.
| Text-authoring concern | Proposed treatment and falsification gate |
|---|---|
| First useful calculation | Inline arithmetic and local definitions are sufficient; a reusable definition or library publication is optional. An engineer can create the one-value and two-duration examples from a blank source bundle using documented admission, with no form-only operation. |
| Identity noise | Initial authoring may omit newly allocated IDs; references use readable aliases. Stable IDs remain in accepted declarations and must round-trip. Evaluate both initial and stabilized files; omitting UUIDs from this report is not evidence that the real files are uncluttered. Folding is supplementary, not a requirement for understanding an ordinary editor's text. |
| Hidden context | Every binding has one explicit case. Property names, unit references and case blocks carry meaning; they must not be removed merely to shorten text. A property read cannot fall back to another case or UI selection. A diagnostics client can locate the case, property and expression token responsible. |
| Repetition across cases | D repeats unchanged inputs and derived expressions. With 1,000 applicable properties and 20 complete cases, that can mean 20,000 binding rows. This is a material design cost, not solved by a search box or collapsed list. Compare B's baseline plus explicit overrides using the same task and provenance display; reverse D's preference if repetition dominates comprehension or causes divergent copied formulas. |
| Locality and file organization | Existing explicit source bundles/includes should let authors group properties/cases/definitions into files. Analysis extensions must retain exact authored bytes and targeted token edits, with stable references after a declaration moves between supplied files. Splitting files alone does not solve the current global alias namespace's cognitive cost; scoped naming would need a separate deliberate language decision. |
| Reuse without expanded clutter | Local calculations and pinned imported definitions need one documented reference form each, with no duplicated editable expansion of sealed definitions. Package transport and import spelling remain shared library-design obligations. A text-only engineer must be able to supply the declared package bytes and pins, not rely on an invisible desktop cache. |
| Meaningful notation | The seven-entry dimension vector is compact but opaque without its fixed order. Compare it with named nonzero dimensions such as dimension { time: 1; } before freezing syntax. The latter is an alternative spelling proposal, not a second admitted grammar. Similarly, repeated bindings wrappers and prefix-heavy declarations warrant user comparison; do not add shorthand whose case or type resolution becomes implicit. |
| Human and AI edits | The normative extension must define precedence, name resolution, ID retention, canonical exact literals and located diagnostics, and provide complete examples. A client following that specification must predict admission and evaluation without private Rust structures or GUI state. A one-input edit should leave unrelated source bytes and accepted identities unchanged. |
Use two authoring evaluations after the semantic choice: a complete small OA/SA example and a generated dense source bundle containing at least 1,000 properties, 20 cases and 100 reusable definitions. Those are proposed stress fixtures, not claims about current capacity. Record source size, changed lines for one assumption, task completion, wrong-case edits, diagnostic locality, and parse/apply/evaluate latency under stated hardware. Include moving a definition between files, a parameter rename retaining identity, adding an alternative, a deliberately invalid unit change followed by repair, and portable save/reopen. Compare D with B before treating D's source ergonomics as settled. A larger standalone textual workflow audit is outside this assignment.
4. Bounded Q1 semantics
4.1 Admission and expression typing
An accepted case may contain explicit unbound inputs, empty definition bodies and empty checks with completeness warnings. Every live property/unit/kind/calculation/constraint/subject reference must resolve to the correct kind. Every property reference reachable from a case expression must have a binding row in that case; its row may be None. Missing rows are a structural error, which a graphical planner can resolve by explicitly adding visible unbound input rows in the same batch. Unknown identities, wrong types, recursive definitions and cyclic case-property dependencies reject the whole candidate. A definition may use parameters and other definitions, never Property nodes.
Calculation call graphs and case dependency graphs must be acyclic even if a syntactic branch is currently unused. Both branches/operands are statically type checked. Dynamic if, && and || use ordinary left-to-right conditional evaluation: only a known condition/left Boolean can select or short-circuit. A missing/error condition propagates; it is not converted to false. Thus true || unknown is true because the unknown branch is unnecessary, while unknown || true remains unresolved under this explicitly ordered evaluation contract. Reports identify the dependencies actually consulted. That distinction needs source/UI guidance and a falsifier test.
Lists are finite, flat and homogeneous. Empty list typing comes from a declared target/parameter type. Sum takes a homogeneous numeric or linear-quantity list and an explicit typed initial value; empty sum returns that initial value. There is no implicit “sum all children,” open-ended query or dynamic collection discovery. Property aggregation over architecture topology is a separate future design, not an assumed behavior of sum.
4.2 Exact numbers
Q1 represents a rational as normalized integers n/d, d > 0, gcd 1, with zero represented only as 0/1. Canonical wire integers have no plus sign or leading zeroes. Decimal source literals are converted arithmetically to rationals; they never pass through f64. The canonical writer can always emit an integer when d == 1 or ratio(n, d) otherwise; ratio is a literal constructor, and division is a separate expression operation. Authored decimal spelling is preserved by ordinary source editing. A terminating decimal may be longer than the allowed literal token, so canonical serialization must not insist on decimal expansion. Noncanonical wire rationals reject instead of being silently rounded or ambiguously compared.
Proposed reference profile: at most 4,096 bits for each reduced numerator/denominator, 1,234 decimal digits in a numeric token's mantissa or canonical ratio component, absolute decimal exponent at most 128, expression depth at most 128, at most 65,536 expression nodes per case/definition closure, list length at most 1,024 and call depth at most 32. Signs and punctuation are not decimal digits. The actual 4,096-bit bound still applies; not every 1,234-digit integer fits. Integer powers are limited to -16 through 16. These are reviewable engineering limits, not measured performance claims. Operations use bounded intermediates, normalize and then enforce the stated result bound; inputs and temporary allocation are bounded before multiplication/division. Crossing a computational bound reports NumericLimit, never a truncated value.
Source, wire and model admission must share these value limits. The earlier 256-digit source proposal was inconsistent with a 4,096-bit admitted literal and is rejected: an accepted Expr::Number containing 10^300 must serialize back to the same literal AST. The integer/ratio fallback avoids the exponent bound and also handles, for example, 1 / 2^4095 without emitting 4,095 fractional digits. Exact values at both 4,096-bit boundaries must survive model-to-source-to-model and JSON round-trips; a formatter may not rewrite a literal into an arithmetic AST to evade its literal limits.
Addition/subtraction/multiplication/division and bounded integer powers are exact. Division by zero and zero to a negative power fail evaluation. 0^0 is explicitly rejected in Q1. Comparisons use rational arithmetic; no global epsilon exists. Existing DataValue::Integer remains i64 and retains its current precision/boundary rules. There is no automatic binding to payload type defaults and no implicit conversion of an analysis result into DataValue; a future adapter must check integrality/range/type exactly.
Unary minus/absolute value accept Number or linear quantity; logical negation accepts Boolean. Arithmetic and ordering reject Booleans/lists. Equality/inequality accepts matching Boolean types or compatible numerical scalar types; list equality is outside Q1. Number plus quantity and implicit conversion from a named dimensionless kind to Number reject. Quantity divided by Number preserves the quantity kind; Number divided by a linear quantity yields an anonymous inverse dimension. A quantity power of one preserves its kind, power zero gives Number one when defined, and other powers yield anonymous dimensions. These typing rules apply before evaluation; their numeric zero-domain failures are evaluated separately.
4.3 Quantities and units
Quantity kind identity is the resolved definition identity, not its name, symbol or seven-dimensional vector. Two different kinds may share a dimension and still be incompatible. A unit's declared kind must match the value's type. In Q1, canonical coordinate is magnitude * scale + offset. Linear units require zero offset. Affine units belong to an affine kind with a declared linear difference kind of the same dimension; both coordinates use the same coherent scale basis. Type checking verifies dimension components and arithmetic exponent bounds.
| Operation | Q1 rule |
|---|---|
| Linear add/subtract/compare | Same resolved kind required; convert coordinates exactly. |
| Affine point minus point | Same affine kind; result has its declared linear difference kind. |
| Point plus/minus interval | Interval must have that affine kind's difference kind; result is a point. Interval plus point is allowed. |
| Point plus point, interval minus point, point multiply/divide/power | Reject as an invalid operation. Comparisons between points of the same affine kind are allowed. |
| Number scaling a linear quantity | Preserve kind, with exact scalar scaling. |
| Product/quotient of different linear quantities | Produce an anonymous derived dimension. Do not guess a named physical kind. |
| Linear quantity divided by the same kind | Produce an exact dimensionless Number. |
AsKind(kind, value) |
Only an anonymous derived result with matching dimension can acquire the explicitly chosen linear kind. It cannot silently convert an already named kind into another named kind. |
| Conversion between units | Same resolved kind; exact scale/offset rules. Changing display unit does not mutate the authored literal or its magnitude. |
Dimension exponents are ordered exactly as in the Rust sketch and each admitted component is bounded to -32 through 32. An anonymous derived quantity is an intermediate result, not a declared property/parameter type; assigning it to a named result requires explicit AsKind. This is deliberately more explicit than using dimensional equality to label force-times-distance automatically as either energy or torque. Revisit this authoring burden if a catalog of unambiguous registered kind operations can be independently specified and justified.
Q1 does not admit logarithmic units or nonrational scale factors. A prospective π-based UnitDefinition must not be represented by a rational approximation with an “exact” label. An approximate-domain extension needs a distinct scale/expression representation and a corresponding profile; its source/JSON form and numerical guarantees remain an open design item. Until then degree/radian conversion and transcendental functions receive Unsupported in the capability/workflow layer; unknown syntax in strict source remains a located rejection. This limit is material to release scope.
4.4 Outcomes and revision identity
Admission and evaluation are different operations. An unmet engineering requirement does not make a structurally valid model unsavable.
enum ValueOutcome {
Value(AnalysisValue),
Missing { inputs: Vec<InputLocation> },
Unsupported { operation: String, required_domain: String },
Failed { diagnostics: Vec<EvaluationDiagnostic> },
}
enum CheckOutcome {
Satisfied,
Violated,
Unresolved { causes: Vec<EvaluationCause> },
}
struct EvaluationReport {
case: Id,
model_snapshot: SnapshotIdentity,
definition_environment: EnvironmentDigest,
numeric_profile: ProfileId,
values: BTreeMap<Id, ValueOutcome>,
checks: BTreeMap<Id, CheckOutcome>,
}
Public AnalysisValue is a Boolean, an Exact Number, a quantity {resolved_kind, canonical_coordinate: Exact}, or a homogeneous flat list carrying its resolved element type. Anonymous derived dimensions are internal intermediates only: a declared result/property must acquire its explicit kind before it can produce a public value. Quantity display conversions accompany that result as derived presentation and never replace the authored literal. JSON represents every Exact numerator/denominator as canonical decimal strings, including converted display values.
Cause collections are nonempty for every nonvalue outcome, deduplicated and stably ordered. Missing includes absent input values or admitted empty definition/check bodies. Unsupported is distinct from a failed supported operation such as division by zero. A check returns Satisfied/Violated only for an evaluated true/false Boolean; the other value outcomes become Unresolved with their original classified causes and dependency path. No-check cases report “No checks,” not vacuous whole-model success. A case summary of passed checks is not a claim that every unrelated input is populated.
Q1's admitted AST contains only its supported operations. Consequently an unknown function is a source/admission error, not an accepted Q1 node fabricated solely to produce ValueOutcome::Unsupported. In the first slice, Unsupported belongs to capability or explicit conversion/evaluation requests outside Q1; the value outcome variant is reserved for a future multi-profile contract that can admit the requested operation. That extension must define when admission versus evaluation reports unsupported capability. Neither path implements the missing mathematics.
The core evaluator consumes an immutable model plus fully resolved immutable definition environment and explicit case ID. It performs no command, history operation, filesystem/network access or source rewrite. Dependency plans and results are derived data. A client supplies its captured document/server revision stamp; server code takes that stamp from the captured stored envelope, never from an untrusted claim in a request. Results retain the full environment digest and numerical profile. A result can describe only that snapshot. Async desktop results for superseded snapshots must be discarded or visibly marked stale. An accepted source/comment-only revision still gets the current document/service stamp even if numerical values are identical.
Proposed UI behavior: Evaluate never applies another pending editor. Either evaluate the clearly labeled accepted snapshot or require explicit Apply/Cancel of the analysis draft; select one behavior and test it. API evaluation likewise cannot write model state. Proposed route shape can follow current validation endpoints, returning the captured ETag/revision and structured report; exact route naming belongs to the shared API design.
5. Falsifying worked examples
| Example | Expected result; what it can falsify |
|---|---|
| Nominal/degraded duration | Nominal 750 ms + 1 s = 7/4 s, check <= 2 s is Satisfied. Degraded uses the same property IDs, binds 1250 ms + 1 s = 9/4 s, and is Violated. Evaluating either cannot change or read the other's bindings. |
| Decimal and fractional arithmetic | 0.1 + 0.2 == 0.3 is true; ratio(1,3) + ratio(1,6) = ratio(1,2). Normalized results and exact wire strings are independently predicted, without consulting the evaluator. |
| Literal serialization closure | An admitted exact literal 10^300, maximum permitted 4,096-bit numerator, and ratio(1, 2^4095) with the denominator expanded as its integer digits all survive canonical source and JSON round-trips with the same literal AST. Reject an actual 4,097-bit component. A long terminating decimal must use the bounded ratio spelling when needed. |
| Existing large integer | Importing an i64 maximum as an explicitly exact analysis literal preserves 9223372036854775807. Adding one produces the exact rational integer 9223372036854775808, but conversion back into DataValue::Integer must reject. Existing i64 admission must not be changed. |
| Unit mismatch | 1000 ms == 1 s is true. 1 s + 1 kg rejects type checking. A free legacy unit string "s" creates no typed unit identity or conversion. |
| Equal dimension, different kind | Comparing a Torque value with Energy rejects even though dimensions agree. AsKind(Energy, force * length) is an explicit dimension-checked assignment; directly AsKind(Energy, torque) rejects. |
| Affine temperature | With explicit point/difference kinds and rational units: 20 Celsius-point converts to 293.15 Kelvin-point; 30 Celsius-point minus 20 Celsius-point gives 10 Kelvin-interval; adding that interval to 20 Celsius-point gives 30 Celsius-point. Adding two temperature points rejects. |
| Missing/error/false | A declared duration input bound to none makes its dependent budget Unresolved/Missing. A known denominator zero gives Unresolved/Failed(DivisionByZero). A computed 9/4 s against 2 s is Violated. None may be displayed as a successful structural validation or the others' outcome. |
| Everyday nonrational math | 30 deg → rad and sin(30 deg) are Unsupported under Q1, not an “exact” decimal π conversion. A later approximate profile must independently demonstrate results near π/6 and 1/2 with its promised numerical guarantees. This is an open release gate. |
| Identity and purity | Rename a calculation parameter and its unit alias: stable parameter/definition identity and results remain. A calculation definition containing a project Property reference rejects. A recursive call rejects, including inside an unused branch. |
| Conditional evaluation | A well-typed `true |
| Library revisions | Two cosmetic import aliases resolving to the same digest/member/dependency closure yield the same definition identity. A changed pinned revision is not automatically the same quantity type because a member name/UUID survived. Rebinding is explicit and invalidates results. |
| Cosmetic package update | Under digest-based kind identity, changing only a package comment still makes its unchanged Duration definition a different kind. Adding old/new Duration values rejects and AsKind cannot bridge them. If the intended selective-update workflow requires these values to mix, the conservative identity rule fails that workflow and an explicit compatibility design is required. |
| No automatic pruning | Deleting a referenced engineering property or definition without removing/rebinding dependent formulas rejects the whole batch. No term is silently deleted from a sum or constraint. An explicit complete replacement batch may succeed even if its intermediate command sequence is temporarily incomplete. |
6. Integration and the library boundary
The sibling library proposal uses Local(Id) or import/package/member references. An ImportId's pinned complete dependency closure is immutable: upgrade creates a new import and explicit selected-use rebindings. A resolved definition key includes exact package digest, member identity and dependency closure; alias spelling does not participate. Stable logical origin (PackageId, MemberId) remains useful for correspondence, but is not sufficient for type/evaluation equality across revisions. Definitions referenced by Q1 never fetch or resolve “latest.”
Exact evaluation provenance and quantity type compatibility need not ultimately be the same equivalence relation. Treating the full package digest as kind identity is conservative but makes even comment-only repackaging incompatible. Before library release, compare (1) explicit versioned compatibility declarations with checked conversion bridges, (2) a specified semantic definition fingerprint including its semantic dependency closure, and (3) retaining strict identity and requiring all interacting uses to be rebound together. Option 1 needs a trust and validation contract; option 2 needs a normative canonical semantic form and deliberate treatment of labels/metadata; option 3 can defeat selective updates. No alternative is ratified here. Results must retain the exact package/environment digest whichever compatibility policy is selected, and same names or dimensions alone remain insufficient. The bounded Q1 slice has no cross-revision bridge.
The evaluator's minimum interface is a typed resolver returning a validated QuantityKind, Unit or Calculation plus its resolved identity/environment evidence. Root-owned library code chooses package transport/catalog envelopes. Neutral definitions may reference each other through that resolver. Current layer-owned DataType/Interface library mounts, if selected by the sibling design, remain an explicit compatibility adapter; analysis must not assume that TypeRef::Named(Id) is already neutral or that mounted architecture instances are pure definitions.
| Existing boundary | Required integration behavior |
|---|---|
| Model identity | New analysis Elements enter the current global IDs/aliases. Local neutral definitions need identity/name/alias services and collision rules in their catalog. Parameter IDs stay scoped to their definition. Imported definition identity must never be confused with a local Element UUID. |
| References and deletion | Add typed Model/Definition/Parameter reference traversal for Expr. Existing UUID visitors may wrap Model references but cannot blindly rewrite all UUID-shaped data. Analysis subject deletion either rebinds/removes the declaration and affected bindings/checks in an explicit batch or refuses with impact. Do not reuse existing list-pruning rules to drop an expression operand. |
| Layer and ownership | Property subjects, case bindings and documented constraints stay in the Element's OA/SA layer. Checks belong to a same-layer case. Neutral definitions cannot capture model records, so permitting a DefinitionRef does not weaken ordinary same-layer references. |
| OA↔SA transition | Map subject/property/case/check identities and all Expr::Property/documented-constraint references through explicit counterparts. Calculation/unit/kind pins remain the same neutral definitions. Never remap ParameterIds as model IDs or copy a neutral definition into OA/SA. Cases/checks require deliberate new catalog/closure rules and exact forward/reverse tests. |
| Source and JSON | Introduce a deliberate next schema/language version with closed records, AST grammar, located diagnostics and schema fixtures. Source token ownership must preserve comments and rewrite stable property/definition/parameter references correctly. Generic raw-string replacement is insufficient. |
| History and recovery | Exact Project+SourceBundle snapshots include accepted definitions/import pins and analysis ASTs. Raw invalid expressions remain drafts. Add closed typed analysis facets/binding keys to semantic review rather than arbitrary JSON patches. Historical imported references must retain enough original pin/origin information to be readable after a live import is removed, without validating them as live references. |
| Publication and API | Analysis requests operate on captured ETag-qualified snapshots. State-changing analysis/library commands retain current atomic admission and no-op semantics. Schema clients must see real definitions, binding types, numerical representation and classified results; an opaque expression string is not the contract. |
| Legacy migration | Preserve source7 Constraint/guard/event/message prose and unit strings exactly. Add no heuristic parsing, unit guessing or default numerical values. Structured quantity use in payload DataValue/TypeRef is a further integration slice; these engineering-property examples alone do not prove typed payload parity. |
7. Exact first slice, remaining decisions and revisit evidence
The first production slice proposed for root approval is one Q1 duration budget workflow in both OA and SA, including exact numbers, local neutral Duration/second/millisecond definitions, two explicit cases sharing typed properties, inline expression, reusable two-parameter calculation, formal check, GUI/source/REST authoring and exact history/recovery. It must not be released as the entire quantity/calculation capability merely because it passes.
Acceptance must establish all of the following:
- Independently construct the complete nominal/degraded models and sources and obtain exactly 7/4 and 9/4 seconds, with different true/false checks and stable shared property identities. Demonstrate reusable call parameter identity independently of names.
- Drive the same creation/change through graphical controls, source and real HTTP. Compare full models, accepted source bytes, references and result stamps. Evaluate alone changes no model, revision or Undo/Redo state.
- Reject wrong layer/kind/units, duplicate/missing parameter arguments, missing binding rows, definition capture and cycles atomically. Retain admitted explicit
noneinputs and show Missing distinctly from False and DivisionByZero. - Exercise exact decimal/fraction/i64-boundary examples and numerical limits, including literal AST/source/JSON closure at 4,096-bit boundaries and the long terminating-decimal counterexample. Check read-only unit conversion versus changing an authored unit literal. No f64 parse/round-trip is permitted in the Q1 evaluator or exact wire adapter.
- Save, Undo, Redo, reopen and recover a raw invalid expression using independently retained complete snapshots. Changing valid UUIDs while preserving names/numbers must fail identity assertions. Pending other editors must not be implicitly applied by Evaluate/navigation.
- Exercise creation/editing at minimum and wide native sizes, with a dense model and duplicate names. Test D against the direct-baseline/explicit-override alternative using the action/context-error criteria above. All property/case/function/parameter/unit choices must be reachable without traversing global homogeneous lists.
- Demonstrate honest Unsupported behavior for degree/radian/trigonometric requests; keep their approximate-domain acceptance and full structured payload/library integration visibly open. Unsupported is a successful refusal test, not evidence that the requested operation is implemented.
- Complete the small source-only workflow from a blank supplied bundle using only the published specification and admission API. Include subject declarations, definitions, both cases, inline and reusable calculations, checks, stable parameter rename, split-file edit, invalid-input repair and save/reopen. Inspect the real stabilized text for identity/boilerplate cost. Run the section 3.4 dense fixture and compare D with B before claiming that the analysis notation supports large-model authoring comfortably.
| Consequential unresolved choice | Evidence that should decide or reopen it |
|---|---|
| D versus baseline values plus overrides (B) | Native and text-only task comparison including ordinary context-independent properties, creation overhead, repeated assumptions/formulas, stabilized-source noise, propagation surprises and wrong-context edits. Reverse preference if explicit complete case bindings cause more confusion/work than clearly labeled baseline inheritance. |
| Q1 alone versus F versus Q+F release scope | Representative engineering formulas must include angular conversion and transcendental cases, not only rational budgets. Q1 cannot win a claim of broad capability by excluding these tasks. Freeze a verified approximate profile before claiming their support. |
| Typed subject association versus true semantic ownership | Deletion, navigation and property discoverability tests on both Element and Relation subjects. Avoid changing parent semantics merely to reuse an existing tree renderer. |
| Explicit anonymous-dimension AsKind versus registered kind operations | Force/acceleration/energy/torque examples and authoring measurements. A shortcut is acceptable only if the kind algebra is unambiguous and versioned, never inferred from display names. |
| Structured quantity types in existing data/payload contracts | Real message/default/type workflows need a deliberate shared QuantityValue and type-reference design. Retaining old annotations is compatibility, not completion of that integration. |
| Definition/package compatibility and historical evidence | Library revision/mount design and independent review must prove pin provenance, selective updates and historical readability. Resolve the unchanged-Duration/comment-only-repackaging falsifier explicitly; exact evaluation provenance must survive any reviewed cross-revision compatibility policy. Do not silently accept same-name or same-member-version changes as type equivalence. |
The root should record the selected alternatives, rejected options, open approximation/payload/library work and resulting release criteria in the durable ledgers. The next highest-information step is independent criticism of these examples and the simple-property authoring flow, followed by one agreed vertical implementation. No statement in this report closes the user's broader goal.