Skip to content

feat(dynamic-ui): complete native Pantry workflows - #258

Merged
veryCrunchy merged 19 commits into
mainfrom
feat/native-pantry-workspace
Jul 31, 2026
Merged

feat(dynamic-ui): complete native Pantry workflows#258
veryCrunchy merged 19 commits into
mainfrom
feat/native-pantry-workspace

Conversation

@veryCrunchy

@veryCrunchy veryCrunchy commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

  • make nested dynamic-app workspaces follow verified parent, collection, state, and record relationships
  • render contract-provided icons, colors, descriptions, enum options, recurrence controls, switches, and searchable relation pickers
  • add permission-aware create, edit, completion, archive, restore, trash, and confirmed permanent-delete workflows without Pantry-specific production adapters
  • preserve exact-version read state and in-progress form and reorder drafts across recreation while requiring fresh live verification before enabling writes
  • add reusable synthetic desktop and phone visual QA for neutral contract-driven app data, including a showcase-quality desktop capture
  • add a tightly scoped debug-only sandbox mutation gate for end-to-end emulator validation

User impact

Pantry houses, lists, items, categories, stores, archive, restore, and trash now behave as native adaptive workflows on Android and desktop. Users select meaningful options and related records instead of entering raw enum values or IDs, and item-provided icons and colors are displayed directly while descriptions remain descriptive text. Large relation datasets remain searchable without eagerly composing every option.

Protocol and safety

Mutation ownership comes from verified read-response identity schemas, exact action provenance, verified relationships, and affirmative record capabilities when the contract exposes them. Relationship heuristics remain presentation-only and cannot authorize writes. Empty or missing request schemas never gain inferred payload fields. Optional collection page sizes honor declared defaults and inclusive bounds, while unsafe values are omitted in favor of the server default. Canonical record IDs are validated before any path-bound control is exposed.

Relation choices are cached by exact parent binding, stale-scope choices are excluded, and failures remain visible with targeted retry. Destructive actions require confirmation. Last-known contracts retain reads but expose no mutation controls until the current versions are verified, including after discovery exceptions. Ambiguous command, form, and directly confirmed action outcomes trigger authoritative reconciliation and suppress blind retry. Generic send, share, and merge writes remain unavailable without operation-specific recovery. Same-account artwork redirects are resolved by Android and desktop transports before app-path validation.

Repeatable structured fields preserve scalar, explicit JSON null, and absent states independently. String-array mutations are exposed only for the exact unconstrained schema subset the native editor validates; constrained arrays fail closed. Pending reorder edits survive activity recreation only when the restored identity list is a bounded, complete permutation of the current authoritative plan.

Validation

  • contract acquisition tests
  • full desktop test suite, including focused structured-field, descriptor-compiler, and lifecycle coverage
  • Android debug unit tests and release lint
  • Android debug APK and desktop distributable builds
  • repository hygiene and fresh synthetic Compose capture checks
  • website capture, generated-content, and integration tests
  • visual inspection of the neutral desktop and phone dynamic-workflow captures
  • live writable end-to-end Pantry 0.23.0 validation on an isolated disposable sandbox covering category, list, and item creation; relation selection; completion and reversal; item deletion; list soft-delete and permanent-delete; and category deletion
  • production source scan confirming there are no Pantry-specific behavior branches

Scope

This is the reusable native checklist and nested-collection foundation. It advances the broader Pantry presentation issue while keeping the remaining visual redesign and other Pantry surfaces independently reviewable.

Advances #252
Advances #98

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 935281f285

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2e7bd4401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt Outdated

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

firstResponse.location
?.let { location -> dynamicAppAssetRequest(descriptor.app.id, location) }
?.let { redirectedRequest -> services.executeNextcloudApi(session, redirectedRequest) }

P2 Badge Resolve same-origin artwork redirects before validating paths

When an app artwork response uses a relative Location or an absolute same-origin URL, this passes the raw header to dynamicAppAssetRequest, which accepts only strings beginning with /apps/<id>/ or /index.php/apps/<id>/. The redirect is therefore discarded and the original empty 3xx body is decoded, so icons and artwork consistently fail on servers or proxies emitting either legal redirect form; resolve the header against the account origin in the transport layer, then enforce the existing app-path restriction.

AGENTS.md reference: AGENTS.md:L143-L144

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@veryCrunchy

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

method in setOf(HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH) &&
listOf("create", "new", "update", "edit").any(semantics::contains) -> recipeEditProperties()

P1 Badge Do not invent recipe write schemas

When a recipe create or update operation declares an empty object schema, this branch replaces the missing contract evidence with a hard-coded set of fields and exposes them as a high-confidence writable form. A sparse or unresolved schema does not establish that the installed app version accepts fields such as name, recipeIngredient, or tool, so submissions can use an invalid payload shape; keep the action unavailable until those properties come from a verified contract or versioned adapter.

AGENTS.md reference: AGENTS.md:L114-L116


val type = (schema as? JsonObject)?.get("type")?.let { it as? JsonPrimitive }?.contentOrNull
return INITIAL_COLLECTION_PAGE_SIZE.takeIf { type == "integer" || type == "number" }?.toString()

P2 Badge Honor declared limits when choosing page size

For any optional numeric limit, pageSize, perPage, or maxResults parameter, this unconditionally injects 50 without reading the schema's default, minimum, or maximum. An otherwise valid endpoint whose declared maximum is below 50 will therefore reject every initial collection load; derive a value within the declared constraints or omit the optional parameter and use the server default.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt Outdated

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1bba97adfa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 495d1038ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebaaa5a723

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

navigationHistory = navigationHistory + DynamicNavigationSnapshot(

P2 Badge Bound saved nested-navigation history

When a dynamic contract permits a long nested drill-down, every transition appends another snapshot without a limit, and each snapshot retains the complete selected NativeRecord plus its binding values. Because the containing Screen.AppInfo is serialized by screenSaver into rememberSaveable, sufficiently deep or data-rich navigation can exceed Android's saved-state transaction budget during activity recreation, causing restoration loss or TransactionTooLargeException. Bound the history and save lightweight resource/record identities rather than complete records.

AGENTS.md reference: AGENTS.md:L250-L256

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

val response = if (firstResponse.status in 300..399) {
firstResponse.location
?.let { location -> dynamicAppAssetRequest(descriptor.app.id, location) }
?.let { redirectedRequest -> services.executeNextcloudApi(session, redirectedRequest) }

P2 Badge Preserve encoded queries when following artwork redirects

When a same-account artwork response redirects to an app path whose query contains normal percent encoding or a padded signed token, this follow-up passes the encoded Location through dynamicAppAssetRequest, whose query validator accepts only unreserved characters. The redirect is consequently discarded and the original 3xx response produces no image; follow the validated same-app redirect in transport or parse and decode its query once before constructing the typed request.

AGENTS.md reference: AGENTS.md:L137-L144

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/DynamicNativeRuntime.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b292f432c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f8db8b3b06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@veryCrunchy veryCrunchy added this to the 0.5 Adaptive apps milestone Jul 31, 2026
@veryCrunchy veryCrunchy added priority:P1 Required for the pre-release product experience area:dynamic-apps Adaptive contracts, semantic UI, and app integrations area:ux Navigation, accessibility, responsive design, and interaction type:feature New product capability platform:android Android-specific implementation or validation platform:desktop Desktop-specific implementation or validation needs-design Requires interaction or visual design before completion needs-protocol-review Requires protocol or upstream source verification labels Jul 31, 2026
@veryCrunchy
veryCrunchy merged commit 0220047 into main Jul 31, 2026
2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ba9bc4bba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -1975,7 +4481,7 @@ private fun GenericRecordBoard(
is NativeActionExecutionResult.Success -> {
createTarget = null
actionMessage = "Card created in ${target.lane.title}. Refreshing the board..."
onActionSucceeded?.invoke()
onActionSucceeded?.invoke(target.action)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Block retries after unknown board creates

When a board create receives a transport exception or 5xx after the server accepted the request, DynamicNextcloudActionExecutor returns Failure(outcome = Unknown), but this board-specific path invokes reconciliation only for Success; the failure branch leaves the create dialog open and clears busyRecordId, so pressing Create again can duplicate the card. This separate board-create callback is fresh evidence beyond the previously reported standalone-form path; route unknown outcomes through authoritative reconciliation and suppress resubmission until it completes.

AGENTS.md reference: AGENTS.md:L187-L194

Useful? React with 👍 / 👎.

relationContext,
)
},
paging = null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Page relationship choices in batch dialogs

When a verified related collection contains more records than its initial page, the new batch loader returns only result.records from the initial request and this batch-specific picker explicitly sets paging = null; its search therefore cannot reach any later category, store, user, or other relation. This is fresh evidence in the new batch path beyond the earlier ordinary-form pagination issue; carry the continuation into the dialog or provide server-side search so users can select every valid relationship instead of being limited to the first page.

AGENTS.md reference: AGENTS.md:L235-L242

Useful? React with 👍 / 👎.

Comment on lines +279 to +283
"string" -> if (allowed != null) {
RepeatableObjectInputScalarKind.Enumeration
} else {
RepeatableObjectInputScalarKind.String
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate formats in repeatable object fields

When a repeatable object declares a string field with a semantic format such as date or date-time, this mapping reduces it to an ordinary string field; canonicalJsonValue subsequently checks only length and control characters, so values that violate the exact request schema are submitted. Map supported formats to their validating field kinds or withhold repeatable-object editing for formats the serializer cannot validate.

AGENTS.md reference: AGENTS.md:L173-L183

Useful? React with 👍 / 👎.

Comment on lines +136 to +140
.minByOrNull { field ->
when (field.id.lowercase()) {
"databaseid" -> 0
"id" -> 1
"uuid" -> 2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Withhold relationships with ambiguous parent identities

When a heuristically matched parent resource exposes more than one identity field, such as both databaseId and id or uuid, this fixed ranking silently chooses one without contract evidence that the child's foreign-key field references it. The relationship picker then submits that chosen value, so an item can be attached to the wrong category, user, or other parent identity; require a unique type-compatible identity or a verified link instead of ranking ambiguous IDs.

AGENTS.md reference: AGENTS.md:L154-L163

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:dynamic-apps Adaptive contracts, semantic UI, and app integrations area:ux Navigation, accessibility, responsive design, and interaction needs-design Requires interaction or visual design before completion needs-protocol-review Requires protocol or upstream source verification platform:android Android-specific implementation or validation platform:desktop Desktop-specific implementation or validation priority:P1 Required for the pre-release product experience type:feature New product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant