Page MenuHomePhabricator

unresolved language argument reference in constructed monolingual stringset
Open, In Progress, HighPublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

What happens?:

  • this test fails
  • the actual output suggests it's not resolving the argument reference (or a function call) for the Z31K1 of the constructed Z31.

What should have happened instead?:

  • the test should pass?

Possibly related to T420998

Details

Event Timeline

Change #1264828 had a related patch set uploaded (by Cory Massaro; author: Cory Massaro):

[operations/deployment-charts@master] wikifunctions: Upgrade orchestrator from 2026-03-25-132654 to 2026-03-30-195027

https://gerrit.wikimedia.org/r/1264828

Change #1264828 merged by jenkins-bot:

[operations/deployment-charts@master] wikifunctions: Upgrade orchestrator from 2026-03-25-132654 to 2026-03-30-195027

https://gerrit.wikimedia.org/r/1264828

DSantamaria changed the task status from Open to In Progress.Apr 1 2026, 6:01 AM
DSantamaria triaged this task as High priority.

Change #1266273 had a related patch set uploaded (by Jforrester; author: Jforrester):

[operations/deployment-charts@master] wikifunctions: Upgrade orchestrator from 2026-03-25-132654 to 2026-03-31-162258

https://gerrit.wikimedia.org/r/1266273

Change #1266273 merged by jenkins-bot:

[operations/deployment-charts@master] wikifunctions: Upgrade orchestrator from 2026-03-25-132654 to 2026-03-31-162258

https://gerrit.wikimedia.org/r/1266273

Why is the v2 parent removed? I thought this worked in v1.
I'm using the v2 parent to keep track of dev progress on recent fixes after the v2 shake up.

Hey @99of9 ,
We are about to close our previous quarterly goal for the v2 composition and are moving this work as Essential-Work into the current quarter; it's more of a reporting thing.

Adding it to essential work sounds excellent. But if fixing v2 issues was part of the quarterly goal, isn't it okay to also leave this there as a (so far) unmet component of the goal?

We are going to fix it, just we are wrapping up the v2 and fixing the bugs coming out of this new feature as part of our essential work instead of as part of a quarterly goal

Thanks for bringing this issue to light, @99of9. I've investigated. I notice that the first then clause of the composition produces a Monolingual stringset with Z31K1/language as a literal (even though its value was input as a reference in this test). I discussed with the team whether this is acceptable behavior of the Orchestrator, and the answer is yes: the orchestrator is returning the correct thing, and is allowed to return any legit form of that thing.

Accordingly, what's needed is an equality function for Monolingual stringset that allows for both reference and literal representations of Z31K1/language. The best way forward is this:

  1. Create a new equality function for comparing 2 instances of Z60.
    1. I propose to make this a built-in; It's easiest and most performant that way.
  2. Use that function to create a new equality function for comparing 2 instances of Z31.
    1. This would replace identical monolingual stringset Z32758, and would allow for different representations of the nested Z60/Natural language objects.
    2. This could be a built-in or not; TBD.
  3. Change Z32765 to use the new equality function (2).
  4. Update orchestrator code so it always creates a value for Z60K2, whenever it produces a Z60 literal.
    1. In this way, it will also be possible to construct literal expected values for Z60s that match what has been produced.

(4) isn't needed to fix the immediate problem with this test, but is needed to help clear up related problems, such as T420998.

I will create tickets and discuss prioritization with team leadership in the coming week.

One final note: how much we resolve Z9s is a large part of the differences between Orchestrator V1 and V2 behavior.

Comments welcome!

Referring to my last comment above:
(1) has been merged (T424289); deployment expected on May 6
(2) has been merged (T424461); deployment expected on May 6

Accordingly, what's needed is an equality function for Monolingual stringset that allows for both reference and literal representations of Z31K1/language. The best way forward is this:

  1. Create a new equality function for comparing 2 instances of Z60.
    1. I propose to make this a built-in; It's easiest and most performant that way.

Perhaps I haven't understood, but doesn't Z22385 show that we can already determine equality of the reference and a constructed equivalent language object? More generally, to show me what's wrong with the current equality function, can you make a test on Z14326 that current implementations fail?

Even if we do need a new Z60 equality function, I'm in two minds about your built-in suggestion. Performance is great of course.

On the other hand, I'm still quite unsatisfied with the way WF locks built-ins away from contributors:

  • Their implementations are invisible to us, so we can't read them.
  • We can't connect and disconnect their tests.
  • Alternative implementations on built-ins may never be connected, and wouldn't ever be run (even if working better on the connected tests?)
  • Do they make it hard for someone to clone WF?

Perhaps built-ins should be implementations, not whole functions??

Hi @99of9 , At present I doubt if I could make a failing test for Z14326. I believe the Orchestrator's current behavior causes all references to Z60/Natural language instances to be resolved to literal form before they are passed into any implementations, due to the fixes made after deploying the V2 composition language. But before deploying those fixes, I think there were some calls to Z14326 that started failing, and Z32765, the initial subject of this ticket, also failed, because a reference and a literal were not recognized to be the same, and that illustrates the point. The point is that Wikifunctions can't make guarantees about the form (reference or literal) in which an instance will come to an implementation. For now, they will be literals, but that could change. (It could change, in particular, because the Orchestrator uses lazy-evaluation of arguments in some places, which is important for performance, and that feature is likely to evolve further.) That's why it's important for us to move in the direction of more fail-safe equality functions that recognize when a reference is identical to a literal.

Recently I raised with the team the question of whether we could provide guarantees about which form might appear in certain contexts, but the feeling is that (a) such guarantees would violate principles of the ZObject functional programming paradigm, (b) limit its flexibility, (c) eliminate significant opportunities for performance improvement, and (d) even if there were such guarantees, implementing and maintaining and documenting them, and users learning about them, could be more troublesome than maintaining more comprehensive equality functions.

Regarding whether a new equality function should be a built-in, I'll comment on that in a separate comment.

In T421468#11885191, @99of9 wrote, regarding built-in functions:
  • Their implementations are invisible to us, so we can't read them.
  • We can't connect and disconnect their tests.
  • Alternative implementations on built-ins may never be connected, and wouldn't ever be run (even if working better on the connected tests?)
  • Do they make it hard for someone to clone WF?

These are good points. In general, going back to early days, the team have felt responsible for providing essential "helper functions" (such as equality functions) for "core types", for performance and other reasons. One of these other reasons is that it makes sense to plan for the update of helper functions in close coordination with the evolution of their core type, to avoid breakages, and it's easiest to maintain that kind of coordination using the dev environment tools and processes available to the maintainers of the code base.

At the same time, the team and I also recognize the undesirable aspects of built-ins that you have expressed, and are generally interested in finding a path that relies less on built-ins over time. We've had discussions about how this evolution could be managed; there are some nontrivial engineering challenges and for now, these ideas are on the back burner.

In the present case, in addition to the default arguments mentioned above, there is a particularly strong performance argument for an equality built-in for Z60, and other types which use Z60 as the type of a key. It's because Z60 has no identity key; i.e. a Z60 literal does not contain its own ZID. That means that a Z60 reference and literal cannot be compared without either resolving the reference to a literal, or somehow looking up the ZID for the language code that's contained in the literal. Because of this, coupled with the fact that there are many Z60 instances used in various places, the performance issue becomes quite significant. As it turns out, the orchestrator maintains a an internal Map of language codes to ZIDs, which allows for such comparisons to be done far more quickly in a built-in implementation. That's what has led me to create built-in implementations for Z60 and Z31 (each instance of which contains a Z60).

Perhaps built-ins should be implementations, not whole functions??

Interesting question/idea; thanks. I wonder if it might have been considered back in the mists of time. I will ask about this in one of our upcoming team meetings.

…The point is that Wikifunctions can't make guarantees about the form (reference or literal) in which an instance will come to an implementation…

It can; it does; it should!

The problem here, I think, is that there is no defined conversion pathway for Z60. Contrast Z40, which is guaranteed by default conversion to arrive in code as a Boolean. Or Z13518, which is guaranteed by custom conversion to arrive in code (barring failure) as a (big)int.

Please also note https://www.wikifunctions.org/wiki/Wikifunctions:Project_chat#Z6830_for_Chinese (which may be a red herring). Clearly, a project with a natural-language focus must support robust language-identifier comparisons in all forms of implementation.

For the record, please also have regard to T344170 when considering whether Z60 should have an identity key. I’m inclined to think we should have both, but I’m not exactly sure how I would define “identity” for a type with multiple different unique identifiers. Presumably Z1002 = "en" = "eng" = Q1860 (= Q22001659 = Q118179251 = Q23014481)? I guess "Z1002" is the identity and the Wikidata item references form an equivalence class, and should perhaps be implemented as a list with type Z6091, or as a canonical representative of that class, based on which the equivalence class can be fetched.