Skip to content

Merge Development into staging, and stop navigating by tab id - #1320

Merged
Paul Lizer (paullizer) merged 14 commits into
feature/admin-settings-iafrom
admin-ia-sync-dev
Aug 19, 2026
Merged

Merge Development into staging, and stop navigating by tab id#1320
Paul Lizer (paullizer) merged 14 commits into
feature/admin-settings-iafrom
admin-ia-sync-dev

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Brings Development into the Admin Settings staging branch so #1319 can merge cleanly, and fixes the last two places that navigated by naming a tab.

Part 1 — merge Development

Development moved on while this work was staged (#1317 and the generated file output fixes), which left #1319 conflicting.

config.py — both branches independently reached 0.260.011. Bumped to 0.260.018 so the merged result is clearly ahead of both.

release_notes.md — both branches wrote a v0.260.011 section from parallel work. Their entries are folded into the one section rather than leaving two headings for the same version. Nothing was dropped from either side.

Everything else merged automatically.

Part 2 — the last hardcoded tab ids

Two places still navigated by naming a tab, and the rework broke both. Neither would have thrown an error; they would just have quietly gone nowhere.

The setup walkthrough

Each of twelve steps mapped to a tab id. Eleven named tabs that no longer exist, so those steps would have moved nowhere and left the admin looking at whatever was already on screen.

Each step already knew which card it was about, so the tab id was a second copy of the same knowledge — free to go stale. Steps now name the card, and openAdminCard() finds the owning tab from the page. scrollToRelevantSection() became redundant and is deleted along with the old map, removing 105 lines.

One case needed judgement: steps 2 and 3 pointed at gpt-configuration, which lives inside the legacy model settings dialog and so cannot be scrolled to while that dialog is closed. They now point at multi-endpoint-configuration — the visible card in the same tab, and the modern place to configure models.

Cosmos throughput validation

Clicked scale-tab to reveal an invalid field. scale is a group now, not a tab, so the field needing attention could be left on a hidden tab with no indication of where to look. It now walks up from the invalid field to its own card, so it goes wherever that field actually lives.

The rule this converged on

Never name a tab. Name the setting and resolve the tab from the page.

A scan confirms no stale -tab literal remains in executable admin JavaScript.

test_admin_settings_walkthrough_targets.py asserts every step points at an element that exists, that no tab id is hardcoded, and that step numbering has no gaps.

Verification

The whole point of this rework is that no setting changes, so that was re-checked against Development after merging rather than assumed:

Development 452 names / staging+merge 452 names
lost: none
added: none
Check Result
Field names vs Development 452 → 452, zero lost, zero added
Regression set (75 files) 32 failures, identical to baseline
Jinja compile 46/46 admin templates
Admin contract suite 46 tests pass
XSS sinks (diff-scoped, as CI runs it) pass

Once this is merged, #1319 becomes mergeable and runs the full gate set against Development.

Paul Lizer (paullizer) and others added 13 commits August 19, 2026 13:57
Actions could be configured with a caller-supplied endpoint while
authenticating with the application's own workload identity. A caller
holding only the User role could save a personal blob_storage action with
an arbitrary endpoint and auth.type=identity, causing the application to
send a token minted for its own managed identity to that destination.

Add a shared Azure endpoint allowlist covering blob, queue, Cosmos,
Databricks, Azure Monitor query endpoints and Entra authority hosts for
the public, US Government, China and Germany clouds. Validate at save
time and again immediately before client construction so actions stored
before this change stop working rather than continuing to leak
credentials.

Enforce each action type's allowedAuthTypes in the shared health-checker
choke point, which previously only populated the action modal. Constrain
Log Analytics custom clouds so authorityHost and endpointOverride cannot
select the token authority or the delegated-token OAuth resource.
Validate the endpoint in the Cosmos test-connection route, which builds
its own client.

Widen blob_storage.definition.json to connection_string, identity and key
and extend the blob modal with an auth selector plus endpoint and account
key fields. Refactor functions_file_sync.py to source the storage suffix
allowlist from the shared module.

The upstream azure-storage-blob bearer-challenge defect that motivated
this report is not addressed here and still needs a fix in
Azure/azure-sdk-for-python.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…-blob-action-hardening

# Conflicts:
#	docs/explanation/release_notes.md

Co-authored-by: paullizer <34814295+paullizer@users.noreply.github.com>
…rdening

Restrict app-identity action endpoints to Azure origins
A telemetry agent retrieved 900 BatteryVoltage1 samples and was asked for a
CSV. The published artifact held 3 rows. A follow-up conversation published 2
rows of server discovery metadata. Three defects combined.

1. build_generated_file_export() let any assistant-rendered table outrank the
   authorized action rows, so the illustrative excerpt the model pasted
   replaced the 900-row dataset. CSV now prefers the authorized rows whenever
   the assistant table is an excerpt of them, matched on shared columns and
   cell values. A table the model composed itself stays authoritative.

2. CSV never received the publication contract JSON and XML already state, so
   the model reported that it could not attach files and pasted a sample
   instead. build_generated_file_output_guidance() now tells the model the
   server serializes and attaches the artifact, and forbids pasting a row
   sample in its place. The one-clarification rule is unchanged.

3. A turn whose reply was the schema clarification still published a CSV,
   assembled from whatever incidental discovery rows the turn produced. That
   turn now publishes nothing and waits for the user's answer.

Version: 0.260.007
…arifications

Follow-up to the same customer conversations. Even with the authorized rows
winning, two requests still had nothing to export.

Discovery calls diluted the dataset. A turn that ran list_instances,
list_parameters, then two pages of list_parameter_history merged all four into
one table with a Source action column, so the artifact carried lookup rows
alongside the samples. Action rows are now grouped by action, so paged calls to
one action stay one dataset, and a retrieval result that dwarfs the turn's other
calls is used on its own.

"create a csv" referring to earlier data had no rows. Action results were read
from the current turn only, so a follow-up request exported nothing even though
the conversation already held the full result set in its stored citations. When
a turn produces no assistant rows and no action rows, the export now reaches
back through recent assistant turns, rehydrates their full citation payloads
from the stored artifact records, and uses the most recent turn that gathered
rows. The reach-back is skipped whenever the turn gathered its own rows, so
rows are never double counted, and the conversation is reauthorized before any
message read.

Answering the schema clarification did nothing. The reply that answers it does
not mention CSV, so the request was not recognized and no artifact was
published. An unanswered clarification now carries the pending CSV request
forward to exactly the next user turn, unless that turn requests a different
format. The passthrough contract established by the original request carries
with it.

Version: 0.260.008
The reach-back read every artifact of a turn just to learn whether it held
rows, which capped the window at 5 assistant messages and made a wider one
expensive. It also took the first turn with any rows, so a newer memory or
discovery call outranked the dataset a request actually meant.

Compaction already leaves the answer on the message. A 54KB telemetry result
is stored on the assistant message as a 677 byte citation that still carries
row_count, the column names, and a remaining_items marker for the dropped
tail. That is enough to decide which action holds the data without reading a
single payload.

Selection is now two phase. select_prior_turn_action_citations() scans the
compact citations already returned by the message query, groups them by
action, and picks the newest group whose recorded rows clear the dataset
threshold, falling back to the most recent rows when no turn has a dataset.
Only the winning group's artifacts are then fetched and expanded.

The window now follows conversation_history_limit from admin settings rather
than a fixed 5, so anything the model can still see in context is reachable by
the exporter, capped at 40 messages.

Selection is pure and lives with the other row-shape logic; the route keeps
authorization and I/O. A guard test pins the compaction assumption so a change
to the compaction limits fails loudly instead of silently degrading the scan.

Version: 0.260.009
…zed-action-rows

fix(csv): build CSV artifacts from authorized action rows
The CSV work left three gaps in the sibling formats and one loose end.

JSON and XML were built only by parsing a payload out of the assistant reply,
so they could never use authorized action rows and never reached back to rows
an earlier turn already gathered. "make that a json" failed exactly the way
"create a csv" used to. build_structured_artifact_rows_payload() now
serializes authorized rows, with the same earlier-turn reach-back and the same
passthrough contract, whenever the reply carries no payload of its own.

The schema clarification gate lived inside the CSV branch, so a turn that
asked a clarifying question could still publish a DOCX or PDF. It now runs
before the format branch and covers every generated file format.

DOCX and PDF guidance never forbade claiming that files cannot be created,
which is the exact sentence that produced the truncated CSV. It now states the
publication contract the other formats already state.

The DOCX and PDF passthrough reason code compared a single row-source literal,
so it was dropped once rows could come from an earlier turn. It now uses the
named row-source set.

Version: 0.260.010
…y-across-formats

fix(artifacts): give every generated file format the same row resolution
…rry-forward

A deployment test surfaced three defects in agent conversations producing CSV
artifacts from a truncating telemetry action.

The model replied "I cannot create or attach a CSV file in this interface" on
the turn that answered a schema clarification, yet the server published the CSV.
Version 0.260.008 carried the pending format forward for publication but not for
guidance, which both chat paths still resolved from the current user message
alone. A clarification answer names no format, so no publication contract ever
reached the model. Both paths now resolve guidance through
_resolve_generated_file_guidance_format, which falls back to the pending format.

A 1,000-row file was produced for a window holding roughly 500 distinct samples.
The agent re-requested the same window with an earlier stop time rather than
paging forward, and action grouping concatenated both responses. Rows an earlier
page of the same action already contributed are now dropped; repeats inside a
single response are kept, because the action counted them as distinct records.

The source action reported truncated results and the file gave no indication it
was partial. Truncation is now detected from the action payload, propagated
through the export payload, summary, and artifact metadata for every format, and
surfaced as a Partial badge on the artifact card. CSV, DOCX, and PDF guidance now
tells the model to page from the last row it holds instead of repeating the range.

The telemetry fixture in test_generated_csv_uses_authorized_action_rows derived
timestamps from index % 60, so its 900 samples were 60 distinct rows repeated
fifteen times, making continuation pages indistinguishable from re-reads.
Timestamps now roll over into minutes, matching the fixture's 15-minute window.

The per-call row cap belongs to the action's own configuration and is unchanged.
…-and-guidance-carryforward

Fix generated artifact paging, truncation disclosure, and guidance carry-forward
Development moved on while the Admin Settings rework was staged, so
the final pull request conflicted. Two files needed resolving.

  config.py       Both branches independently reached 0.260.011.
                  Bumped to 0.260.018 so the merged result is clearly
                  ahead of both.

  release_notes   Both branches wrote a v0.260.011 section from
                  parallel work. Their entries are folded into the one
                  section rather than leaving two headings for the
                  same version.

Re-verified after the merge

  field names      452 on Development, 452 here, none lost, none added
  regression set   32 failures, identical to baseline
  jinja compile    46/46 admin templates
  contract suite   43 tests pass

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Two places still navigated by naming a tab id, and the information
architecture rework broke both.

The setup walkthrough

  Each of twelve steps mapped to a tab id. Eleven named tabs that no
  longer exist, so those steps would have moved nowhere and left the
  admin looking at whatever was already on screen.

  Each step already knew which card it was about, so the tab id was a
  second copy of the same knowledge, free to go stale. Steps now name
  the card and openAdminCard finds the owning tab from the page.
  scrollToRelevantSection became redundant and is deleted, along with
  the old map.

  Steps 2 and 3 previously pointed at gpt-configuration, which lives
  inside the legacy model settings dialog and so cannot be scrolled to
  while that dialog is closed. They now point at
  multi-endpoint-configuration, the visible card in the same tab and
  the modern place to configure models.

Cosmos throughput validation

  Clicked scale-tab to reveal an invalid field. scale is a group now,
  not a tab, so the field needing attention could be left on a hidden
  tab with no indication of where to look. It now walks up from the
  invalid field to its own card, so it goes wherever that field
  actually lives.

test_admin_settings_walkthrough_targets.py asserts every step points
at an element that exists, that no tab id is hardcoded, and that step
numbering has no gaps.

A scan confirms no stale '-tab' literal remains in executable admin
JavaScript.

The rule this rework converged on: never name a tab, name the setting
and resolve the tab from the page.

Verified
  regression set   32 failures, identical to baseline
  admin suite      46 tests pass
  jinja compile    46/46 admin templates

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer Paul Lizer (paullizer) changed the title Merge Development into the Admin Settings staging branch Merge Development into staging, and stop navigating by tab id Aug 19, 2026
@paullizer
Paul Lizer (paullizer) merged commit 3c7f523 into feature/admin-settings-ia Aug 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants