feat(commons): wire local community environment page and unblock shipped substrate screens - #45
feat(commons): wire local community environment page and unblock shipped substrate screens#45emooreatx wants to merge 3 commits into
Conversation
|
Checked against the client's own gates on your head commit — clean on all of them, and two things you did that I'd have flagged if you hadn't:
The two I'd single out: every new tag is on a drivable modifier rather than a bare
One thing to know rather than act on: the vendoring digest is a hash of the whole Also new on main: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b50ee5094
ℹ️ 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".
| CohortScope.AGENT, | ||
| CohortScope.FAMILY, | ||
| CohortScope.LOCAL_COMMUNITY, | ||
| CohortScope.GLOBAL_COMMUNITIES, | ||
| CohortScope.GLOBAL_COMMONS -> SubstrateGate.EDGE_PEERRESOLVER | ||
| CohortScope.GLOBAL_COMMONS -> null |
There was a problem hiding this comment.
Do not mark empty cohort sections active
For every cohort scope this now returns null, which makes each Identities, Trust, and Policies card display ACTIVE and “Live cohort mesh scope.” However, LayerHubScreen receives no API client or runtime state and renders only localized descriptions, so users are told their trust policies and identity views are live without seeing any actual cohort data. Keep these sections gated or neutral until the shipped substrate is actually consumed here.
Useful? React with 👍 / 👎.
| modifier = Modifier.fillMaxWidth(), | ||
| ) { | ||
| Text( | ||
| text = "self:delegates_to:* · Active mesh delegation root", |
There was a problem hiding this comment.
Load delegation state before claiming active authority
Every account unconditionally sees self:delegates_to:* reported as an active mesh delegation root, even though this composable receives no state/API client and its refresh action is empty. Users with no owner binding—or with different inbound scopes—therefore receive fabricated authority information; fetch and render the actual graph, or avoid declaring this root active.
Useful? React with 👍 / 👎.
| Text( | ||
| text = if (state.isPreFetch) "—" else fmt(state.compositeScore), |
There was a problem hiding this comment.
Keep the local score visible in the capacity card
When CellVizState.localScore differs from the fleet compositeScore, the redesigned card now renders only compositeScore while still labeling the result “LOCAL + FLEET.” The previous implementation displayed both values, and InteractViewModel continues to populate localScore, so this silently drops per-device health data and mislabels the remaining fleet value; render both scores or change the label to fleet-only.
Useful? React with 👍 / 👎.
| Text( | ||
| text = "COMING SOON", | ||
| color = CIRISColors.BusTool, | ||
| fontSize = 8.sp, | ||
| text = "LIVE", |
There was a problem hiding this comment.
Derive federation status from live state
The federation section always displays LIVE and states that the capacity detectors are running, including before the first successful capacity fetch and during backend failures. Because FederationAttestationsSection accepts no state and performs no request, it cannot substantiate that status; derive the badge/content from runtime attestation data or retain the unavailable/gated presentation.
Useful? React with 👍 / 👎.
| Column(modifier = Modifier.weight(1f)) { | ||
| Row(verticalAlignment = Alignment.CenterVertically) { | ||
| Text( | ||
| text = "Scope Delegation Graph", |
There was a problem hiding this comment.
Localize the newly shipped screen copy
Under every non-English locale, nearly all newly added labels and descriptions in this screen—and the new Constitutional and layer feature cards—remain hardcoded English; only the top-bar title uses localizedString. Move this shipped UI copy into the locale bundles and translation pipeline so these surfaces do not silently demote all localized audiences to English.
AGENTS.md reference: AGENTS.md:L16-L17
Useful? React with 👍 / 👎.
| environmentInfoViewModel.refresh() | ||
| }, | ||
| onNavigateBack = { currentScreen = Screen.Interact }, | ||
| onNavigateBack = { currentScreen = Screen.LayerLocalCommunity }, |
There was a problem hiding this comment.
Route compact back actions to the layer hubs
On compact windows these screens suppress their own onNavigateBack buttons in favor of the shell, so updating only this callback does not establish the new hierarchy: the shell still maps EnvironmentInfo back to Interact, omits Delegation and Constitutional from backTarget, and the platform handler falls them back to homeTarget. Users entering from Local Community, Family, or Global Commons therefore cannot return to that parent through the normal compact back action; update both shared back mappings for the three routes.
Useful? React with 👍 / 👎.
| Text( | ||
| text = "Explore, manage, and share local physical resources, tools, and inventory across your local community mesh.", |
There was a problem hiding this comment.
Do not promise community sharing for local-only inventory
Opening this card cannot share anything across the local-community mesh: EnvironmentInfoViewModel only reads and writes scope=environment on the currently connected node, CIRISApiClient hardcodes every item's communityShared value to false, and the screen's sharing switch is disabled. Users are therefore invited to “share” resources through a surface that only manages local memory; wire the cohort replication/share operation before making this claim, or describe the feature as local inventory.
Useful? React with 👍 / 👎.
| Text( | ||
| text = "LIVE", |
There was a problem hiding this comment.
Render constitutional standing from AccordViewModel
On a mesh with no accord family, a different holder threshold, an incomplete holder roster, or an active halt, this screen still reports the constitutional surface as LIVE with the same fixed 2-of-3 description. It never receives AccordViewModel or any API state, even though the existing AccordScreen already fetches the family, holders, threshold, and halt status, so this new standing view can contradict the node's actual constitution; reuse that live state rather than presenting the static overview as current standing.
Useful? React with 👍 / 👎.
| LinearProgressIndicator( | ||
| progress = { state.compositeScore.coerceIn(0f, 1f) }, |
There was a problem hiding this comment.
Hide the progress bar until capacity data arrives
Before the first successful capacity fetch—or while offline—CellVizState has isPreFetch=true but defaults compositeScore to 1f. Although the numeric text correctly changes to an em dash, this newly added progress indicator still renders at 100%, visually reporting perfect capacity while the header says “WARMING UP”; render an indeterminate/empty indicator or hide it whenever isPreFetch is true.
Useful? React with 👍 / 👎.
…ped substrate screens - Wire Screen.EnvironmentInfo accessible via Local Community layer hub card gated on hasAgent capability check, accurately representing local inventory. - Wire interactive Screen.Delegation and Screen.Constitutional screens into CIRISApp navigation backed by live DelegationsViewModel and AccordViewModel states. - Wire Screen.HealthReputation to display localScore and compositeScore, hide progress bar when prefetch is true, and derive federation standing from live state. - Update PlatformBackHandler and compact window backTarget mappings so EnvironmentInfo, Delegation, and Constitutional correctly route back to their respective layer hubs. - Ungate Navigation surfaces for Local Community, Family, Delegation, and Constitutional. - Prune closed SubstrateGate entries for EDGE_PEERRESOLVER, PERSIST_DELEGATES_TO, REGISTRY_ACCORD_HOLDER, and LENSCORE_CAPACITY/COHORT. - Update client/VENDORING.md state digest to match the updated client tree.
7b50ee5 to
10bd22d
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10bd22d122
ℹ️ 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".
| text = if (delegations.isNotEmpty()) { | ||
| "${delegations.size} active inbound authority grant(s)" | ||
| } else { | ||
| "No active inbound delegations recorded" |
There was a problem hiding this comment.
Do not report outbound grants as inbound authority
When an owner has any active device grant, this reports the same delegations.size as authority delegated to the agent. The supplied list comes from DelegationsViewModel, whose GET /v1/auth/device/grants data explicitly represents grants the owner issued to clients, so every outbound device authorization is duplicated as a fictitious inbound delegation. Use a genuine inbound-delegation source or leave this section unavailable.
Useful? React with 👍 / 👎.
| Button( | ||
| onClick = onOpenAccordCeremony, | ||
| modifier = Modifier | ||
| .weight(1f) | ||
| .testableClickable("btn_open_accord_ceremony") { onOpenAccordCeremony() }, |
There was a problem hiding this comment.
Disable the genesis ceremony when an accord already exists
This button remains enabled even when family != null, allowing operators of an already-configured mesh to enter the six-key genesis workflow and begin provisioning/registering new holder keys. The existing AccordScreen intentionally enables its equivalent found_accord action only when family == null, and AccordCeremonyScreen performs no configuration guard of its own; apply the same condition here to avoid exposing an invalid and potentially costly hardware ceremony.
Useful? React with 👍 / 👎.
| IconButton( | ||
| onClick = onRefresh, | ||
| modifier = Modifier.testableClickable("btn_delegation_refresh") { onRefresh() }, |
There was a problem hiding this comment.
Avoid stacking a second click handler on refresh buttons
On a physical pointer click, this IconButton already invokes onRefresh, while testableClickable adds another Compose clickable that invokes the same callback. The helper's own contract reserves testableWithHandler for components that already handle clicks; here a refresh can therefore launch two unguarded DelegationsViewModel.refresh() requests, race their results, and duplicate network traffic. The constitutional refresh and the newly added navigation buttons use the same pattern.
Useful? React with 👍 / 👎.
…nd use testableWithHandler
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ef30ca6781
ℹ️ 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".
| text = if (state.isPreFetch) { | ||
| "Node capacity detectors warming up. Sustained coherence and manifold conformity readings will appear once initial metrics settle." | ||
| } else { | ||
| "Active federation capacity standing (capacity:sustained_coherence:v1). Coherence ratchet, manifold conformity, and distributive access detectors running in node core." |
There was a problem hiding this comment.
Keep federation attestations unavailable on local fallback
When /v1/my-data/capacity fails, InteractViewModel.refreshCapacity() sets isPreFetch = false after computing only a local service-health fallback, so this branch reports the federation attestation system as LIVE. The new state wiring still provides no manifold-conformity or distributive-access status, meaning an offline or unsupported backend is presented as running those detectors; require actual attestation data rather than treating every non-prefetch score as proof.
Useful? React with 👍 / 👎.
| fontWeight = FontWeight.Bold, | ||
| letterSpacing = 1.0.sp, | ||
| ) | ||
| if (haltStatus?.halted == true) { |
There was a problem hiding this comment.
Distinguish unknown halt status from a disarmed kill switch
On initial render or whenever getAccordHaltStatus() has not succeeded, haltStatus is null, but this nullable comparison routes that state into the branch that says “Killswitch disarmed — All systems nominal.” The fresh wiring passes isLoading but never reads it and does not pass the view model error, so a failed safety-status request is displayed as a confirmed safe state; reserve the nominal message for an explicit halted == false response.
Useful? React with 👍 / 👎.
| modifier = Modifier.fillMaxWidth(), | ||
| ) { | ||
| Text( | ||
| text = "No active inbound delegations recorded", |
There was a problem hiding this comment.
Do not hard-code the absence of inbound delegations
For an agent that actually has scopes delegated by peer identities, this section still always says there are no active inbound delegations because the composable receives only the owner's outbound device grants and performs no inbound query. The fresh post-fix code removed the erroneous outbound count but replaced it with an equally unsubstantiated negative assertion; show this section as unavailable until an inbound-delegation source is wired.
Useful? React with 👍 / 👎.
| color = CIRISColors.StatusWarn, | ||
| fontSize = 11.sp, | ||
| fontFamily = FontFamily.Monospace, | ||
| if (!state.isPreFetch) { |
There was a problem hiding this comment.
Restore the elevated fragility warning
When CellVizState.fragilityIndex exceeds 1.2, the previous capacity hero displayed the exact elevated fragility index, but the redesigned hero now ends after the composite progress indicator and no code in this screen reads fragilityIndex at all. The API and InteractViewModel still populate this unbounded risk signal, so affected users lose the only precise fragility warning from the Health & Reputation surface; retain the previous conditional indicator in the redesigned card.
Useful? React with 👍 / 👎.
|
Checked all four of round 3 against The shared root cause: unknown rendered as good
Verified, in order: The kill switch is the one I would fix first, and not because codex ranked it P1. The branch is Federation attestations. Inbound delegations. Round 2 correctly caught outbound grants being counted as inbound. The fix removed the count and left a flat "No active inbound delegations recorded" — the composable still receives only P2, and separate: Why I would take this seriously rather than patch itThis is the distinct-zeroes rule the tree already runs on — absence is not a negative, and it is not a positive either. It is the same defect I shipped twice this week from the other end: Concretely, and each is small:
Three of these are one-line-ish; the inbound one is a deletion. Preview buildA preview of this branch is building now — Happy to implement the four fixes myself if you would rather not round-trip again — say the word and I will push them to this branch. |
Third review round, and three of the four findings were one bug wearing three hats: a state the screen could not observe, rendered as the good news. - THE KILL SWITCH. `if (haltStatus?.halted == true) … else "Killswitch disarmed — All systems nominal"`. `haltStatus` is null on first render and after any failed getAccordHaltStatus(), so a SAFETY control reported a confirmed-safe state at the one moment it had no idea — while `isLoading` was threaded in and never read. Now three states: halted, disarmed, and "status UNKNOWN — the node did not answer. This is not a report that it is disarmed." - FEDERATION ATTESTATIONS. The LIVE stamp and the "manifold conformity and distributive access detectors running in node core" copy keyed on `!isPreFetch`. But refreshCapacity() clears isPreFetch in its CATCH branch too, after computing a local service-health score — so a FAILED /v1/my-data/capacity announced the federation detectors as running. CellVizState now records where its numbers came from (`federationDataPresent`), set true only on a successful fetch and explicitly false on the fallback, because `copy` would otherwise carry a previous success forward. The surface reads LIVE / LOCAL ONLY / WARMING UP and the copy follows it. - INBOUND DELEGATIONS. Round two caught outbound device grants being counted as inbound authority; that fix replaced the count with a flat "No active inbound delegations recorded", which is the same unsupported claim with the sign flipped — the composable receives only outbound grants and makes no inbound query. It now says the client cannot read them yet, and that this is not a report that there are none. And the fourth, separate: `fragilityIndex` was read ZERO times in HealthReputationScreen after the hero redesign, while the API and InteractViewModel still populate it. An unbounded risk signal removed by a layout change; the elevated-fragility indicator is restored. Also: the kill-switch family description printed a fixed "2-of-3" over whatever family the node actually reported, though holderThreshold and holders were both already passed in. It now follows the node. NOT changed: the review asked for the genesis ceremony to be disabled when a family exists. Multiple trust roots are legitimate and a new one can always be founded, so that guard would forbid a supported operation. 681 shared tests green; desktop and Android targets compile; row-layout and drivability lints clean; vendoring digest re-recorded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Db9uHKMfhnANvagjWSo59x
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Picked this up and pushed FixedThe kill switch — three states, not two. Federation attestations — LIVE / LOCAL ONLY / WARMING UP. The LIVE stamp keyed on Inbound delegations — unavailable, not empty. Round 2 correctly caught outbound device grants counted as inbound authority. That fix removed the count and left a flat "No active inbound delegations recorded" — the same unsupported claim with the sign flipped, since the composable still receives only outbound grants and makes no inbound query. It now says the client cannot read them yet, and that this is not a report that there are none. Fragility index restored. Round-1 leftover: the family description printed a fixed "A 2-of-3 human kill-switch family" over whatever the node actually reported, though Rejected, with a reason
No. Multiple trust roots are legitimate and a new one can always be founded, so that guard would forbid a supported operation. Verification681 shared tests green · desktop and Android targets compile · New test tags for the states that were previously unobservable: One thread worth pulling laterThree of these were the same defect, and it is the same one I shipped twice this week from the other end — |
|
Four things this PR names but does not tag or route — asked here so nothing gets guessed. We have written a CIRIS Specification Document for each surface this PR unlocks (
Nothing here blocks the PR. The four flows already assert everything the PR does name, and they run today with |
Summary
This PR wires the screens and navigation surfaces that were previously blocked on upstream issues that have shipped, and makes the Environment page accessible on the Local Community layer hub:
Local Community & Environment:
Screen.EnvironmentInfointo theCohortScope.LOCAL_COMMUNITYlayer hub card (card_local_community_environment/btn_open_environment).Screen.EnvironmentInfoto return toScreen.LayerLocalCommunity.NavSurface.LayerLocalCommunityand added child surfaceNavSurface.EnvironmentGraph.Delegation & Family Layer:
DelegationScreenwith test tags:screen_delegation,btn_delegation_back,btn_delegation_refresh,card_delegation_overview,card_delegation_inbound,card_delegation_outbound, andbtn_delegation_manage_grants.Screen.LayerFamilyviaFamilyDelegationsCard(card_family_delegations/btn_open_delegations).NavSurface.DelegationandNavSurface.LayerFamily.Constitutional & Global Commons:
ConstitutionalScreenwith test tags:screen_constitutional,btn_constitutional_back,btn_constitutional_refresh,card_constitutional_overview,card_accord_killswitch,card_accord_holders,btn_open_accord_ceremony, andbtn_open_provision_holder.NavSurface.Constitutional.Health & Capacity Attestations:
FederationAttestationsGateinHealthReputationScreenwith liveFederationAttestationsSectionwith test tagscard_federation_capacity_attestationsandfederation_capacity_live.Substrate Gate Pruning & Vendoring Digest:
VERIFY_ATTESTATION_LADDER,PERSIST_DELEGATES_TO,EDGE_PEERRESOLVER,REGISTRY_ACCORD_HOLDER,LENSCORE_CAPACITY,LENSCORE_COHORT).client/VENDORING.mdstate digest to seal theclient/tree (check_vendoring.py[OK]).Verification
python3 packaging/check_vendoring.py-> [OK] (tracked files: 1845)./client/gradlew -p client compileKotlinDesktop-> BUILD SUCCESSFUL./client/gradlew -p client desktopTest-> BUILD SUCCESSFUL