Goal
Decide whether canonical parsing may discard the literal substitutions that pinned OverPy writes under #!optimizeForSize, given that those substitutions exist to lower the Workshop element count and that the element-count rule in docs/element-count.md does not distinguish them.
Context
Observed while re-running a production project's build comparison (OWBastion/Bastion, Wright 0.2.37, opy-rs provider 0.1.58, pinned OverPy 9.7.10).
Behavior. normalize_value_with_coercions (ADR-0011 decision 2) rewrites False/True, zero vectors and 0 into the canonical value wherever a catalog paramCoercions fact allows it. Emission never writes them back. Parsing OverPy's own output and emitting it again therefore changes it:
| Input (OverPy, en-US) |
After parse and emit |
Set Move Speed(Event Player, False) |
Set Move Speed(Event Player, 0) |
Set Gravity(Event Player, True) |
Set Gravity(Event Player, 1) |
Start Forcing Throttle(Event Player, False, True, False, True, False, True) |
... 0, 1, 0, 1, 0, 1) |
Vector(False, 1, 0) |
Vector(0, 1, 0) |
Validation already accepts the un-normalized forms (contextual_value_matches in values/validate.rs), so normalization is not needed for acceptance. It gives WIR one canonical form.
Why OverPy substitutes. OverPy documents #!optimizeForSize as "prioritizes lowering the number of elements". Its own element count (#!debugElementCount) for three actions with eight small numeric arguments is 12 elements without the substitution and 4 with it, one element per replaced literal. The main entry of the production project totals 30096 elements by OverPy's count. Its Wright output has about 500 fewer False/True literals than OverPy's (1285 versus 787 in zh-CN main, 1198 versus 741 in en-US externalMain), which is about 500 more elements if OverPy's accounting holds.
Conflicting element-count model. docs/element-count.md reduces every direct action argument by one, so 0 and False cost the same, and the analysis runs on the normalized Program, so it cannot see the difference either. OverPy charges a numeric literal argument one element and False, True and Null none. Only the client can say which is right; ADR-0005 describes the capture workflow.
The coercion table itself agrees with OverPy. Of 142 per-parameter canReplace0ByFalse, canReplace1ByTrue, canReplace0ByNull and canReplaceNullVectorByNull marks in OverPy 9.7.10, 140 are present as catalog coercions; the other two are the same parameter under a different argument layout (setPlayerVariableAtIndex). Eighteen further catalog coercions correspond to hard-coded OverPy paths (chase rates, indexed variable index, random.randint). Contents are not the problem; what happens to the values after parsing is.
Locale-dependent result. The zh-CN spelling 开始限制阈值 resolves to the legacy forceThrottle identity, which has no coercions, so its 假 survives while the en-US False is normalized. This is the duplicate-identity problem tracked in #297 and should disappear with it.
Scope
- Obtain client evidence for the element count of the two spellings (a numeric literal versus
False/True/Null in the same slot), using the ADR-0005 workflow or an equivalent capture.
- Decide, and record in an ADR, one of:
- keep normalization and document that parse and emit is lossy for these literals (no element-count guarantee across a round trip);
- keep the substitution spelling through parse and emission where the catalog allows it;
- keep canonical WIR and add an explicit emission-side size optimization driven by the same coercion facts, selectable by consumers.
- Make
docs/element-count.md state the rule the client evidence supports.
Non-goals
Acceptance criteria
- Client evidence, or a recorded statement that none is available, for the element cost of
0 versus False in a numeric argument.
- An ADR records the chosen option and the consequence for round trips.
- If the option changes behavior, regression tests cover parse then emit of the substituted spellings in more than one locale.
docs/element-count.md matches the evidence.
Dependencies
Related: #297, #286, ADR-0011, ADR-0014. The outcome decides how Wright can reproduce OverPy's element count for #!optimizeForSize projects.
Goal
Decide whether canonical parsing may discard the literal substitutions that pinned OverPy writes under
#!optimizeForSize, given that those substitutions exist to lower the Workshop element count and that the element-count rule indocs/element-count.mddoes not distinguish them.Context
Observed while re-running a production project's build comparison (
OWBastion/Bastion, Wright 0.2.37, opy-rs provider 0.1.58, pinned OverPy 9.7.10).Behavior.
normalize_value_with_coercions(ADR-0011 decision 2) rewritesFalse/True, zero vectors and0into the canonical value wherever a catalogparamCoercionsfact allows it. Emission never writes them back. Parsing OverPy's own output and emitting it again therefore changes it:Set Move Speed(Event Player, False)Set Move Speed(Event Player, 0)Set Gravity(Event Player, True)Set Gravity(Event Player, 1)Start Forcing Throttle(Event Player, False, True, False, True, False, True)... 0, 1, 0, 1, 0, 1)Vector(False, 1, 0)Vector(0, 1, 0)Validation already accepts the un-normalized forms (
contextual_value_matchesinvalues/validate.rs), so normalization is not needed for acceptance. It gives WIR one canonical form.Why OverPy substitutes. OverPy documents
#!optimizeForSizeas "prioritizes lowering the number of elements". Its own element count (#!debugElementCount) for three actions with eight small numeric arguments is 12 elements without the substitution and 4 with it, one element per replaced literal. Themainentry of the production project totals 30096 elements by OverPy's count. Its Wright output has about 500 fewerFalse/Trueliterals than OverPy's (1285 versus 787 in zh-CNmain, 1198 versus 741 in en-USexternalMain), which is about 500 more elements if OverPy's accounting holds.Conflicting element-count model.
docs/element-count.mdreduces every direct action argument by one, so0andFalsecost the same, and the analysis runs on the normalized Program, so it cannot see the difference either. OverPy charges a numeric literal argument one element andFalse,TrueandNullnone. Only the client can say which is right; ADR-0005 describes the capture workflow.The coercion table itself agrees with OverPy. Of 142 per-parameter
canReplace0ByFalse,canReplace1ByTrue,canReplace0ByNullandcanReplaceNullVectorByNullmarks in OverPy 9.7.10, 140 are present as catalog coercions; the other two are the same parameter under a different argument layout (setPlayerVariableAtIndex). Eighteen further catalog coercions correspond to hard-coded OverPy paths (chase rates, indexed variable index,random.randint). Contents are not the problem; what happens to the values after parsing is.Locale-dependent result. The zh-CN spelling
开始限制阈值resolves to the legacyforceThrottleidentity, which has no coercions, so its假survives while the en-USFalseis normalized. This is the duplicate-identity problem tracked in #297 and should disappear with it.Scope
False/True/Nullin the same slot), using the ADR-0005 workflow or an equivalent capture.docs/element-count.mdstate the rule the client evidence supports.Non-goals
optimizeForSizeat its own Workshop boundary and adopts the outcome in its own PR.Acceptance criteria
0versusFalsein a numeric argument.docs/element-count.mdmatches the evidence.Dependencies
Related: #297, #286, ADR-0011, ADR-0014. The outcome decides how Wright can reproduce OverPy's element count for
#!optimizeForSizeprojects.