a2ui-project / a2ui-project/a2ui

[BUG]: A malformed path deletes what it is written through in the Swift DataModel, and the shared suite does not run

Aperta
#2,625 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
status: needs-triage
Lingua principale
TypeScript
Stelle
16.4k
Fork
1.3k
Merge medio
2g 13h
PR unite (30g)
134

Descrizione

- [x] I have searched the existing issues to make sure this bug has not already been reported.

## Describe the Bug

The Swift client does not run `conformance/core/data_model.yaml`. It has a hand-written `DataModelPointerConformanceTests` instead, while the Dart client and `web_core` are both driven by the shared suite (#2622 covers the Python client, which was in the same position).

Running the suite against `DataModel` executes 19 of its 37 cases. All 19 pass. The four that fail are the four that write a path through a value which is not a container, and each one destroys data:

| initial | write | result |
| --- | --- | --- |
| `/user/name` is `"Alice"` | `set("/user/name/first", "Bob")` | `{"name": {"first": "Bob"}}` — `"Alice"` is gone |
| `/items` is `["a","b","c"]` | `set("/items/0/foo", "bar")` | `[{"foo":"bar"},"b","c"]` — `"a"` is gone |
| `/items` is `["a","b","c"]` | `set("/items/foo", "bar")` | `{"foo":"bar"}` — **the whole array is gone** |
| `/items` is `["a","b","c"]` | `set("/items/foo/bar", "v")` | `{"foo":{"bar":"v"}}` — **the whole array is gone** |

The last two are the ones to worry about. A single non-numeric segment in a path an agent emits replaces an entire array with an object, and nothing is reported.

`JSONValue.update` auto-vivifies over anything that is not an object or an array, and its array branch builds an object when the key does not parse as an index — which returns in place of the array, rather than leaving it alone.

### It was pinned, which is why nothing caught it

```swift
@Test func subscriptSetAutoVivifiesArrayFromPrimitive() {
var value: JSONValue = "primitive"
value["0/name"] = "Alice"
#expect(value.arrayValue?.count == 1)
#expect(value["0/name"]?.stringValue == "Alice")
}
```

That test asserts the string is replaced. `test_data_model_rejects_write_through_primitive` in the shared suite says the same write is an error, and Dart, `web_core` and Python all reject it. A local unit test and the shared suite disagreed, and the local one was the only one running.

## Steps to Reproduce

```swift
let model = DataModel(initial: .object(["items": .array([.string("a"), .string("b")])]))
model.set("/items/foo", value: .string("bar"))
print(model.get("/items") as Any) // {"foo": "bar"} — both elements gone
```

## Expected Behavior

Auto-vivification fills in absent and null nodes only, and a path through anything else is rejected rather than clearing it.

## Two decisions this needs, which is why the PR only goes half way

The PR attached to this issue stops the destruction: those writes now leave the tree as it is. It deliberately does not make the four cases pass, because both of the remaining steps change public API and are yours to choose.

**1. Can `set` report a rejected write?** `public func set(_ path: String, value: JSONValue?)` returns Void, so a rejected write can only be dropped in silence. Dart's comment on the same branch says it out loud — "dropping the write would hide a malformed path" — and the suite agrees. Making Swift agree means `throws`, a `Result`, or an error publisher on `DataModel`. Which would you want?

**2. Is a per-path observer API wanted?** 14 of the suite's 37 cases attach an observer to a path and assert who was notified. `DataModel` exposes `dataPublisher`, which emits the whole tree, so there is nothing to attach to a single path and those cases cannot run at all. Dart has `watch(path)`, `web_core` and Python have `subscribe(path, ...)`.

Until both are settled, the harness in the PR skips those two shapes — by their shape, not by a list of names, so neither skip can quietly grow — and prints what it left out on every run.

## Environment Details

- **OS**: macOS 15
- **Browser/Platform**: Swift 6, `swift test --enable-swift-testing`
- **SDK/Package Name & Version**: `A2UISwiftCore` at `main`
- **Protocol Version**: v0.9

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

The bug is in JSONValue.update in the Swift client. Start by running the shared conformance suite (conformance/core/data_model.yaml) to see the failing cases. Examine the DataModelPointerConformanceTests and the PR attached to understand the current fix. The decisions needed about error reporting and per-path observers require familiarity with the project's API design and discussion with maintainers.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
swift
Ambito
backend-api-design
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
45/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.