feat(commons): wire local community environment page and unblock shipped substrate screens - #45
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 <[email protected]> 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 |
|
The four CSD flows for this PR's surfaces are now wired into CIRISAgent's five-platform gate ( What they report today, on 0.5.212: every flow reaches its screen and then stops at its first Tags the flows assert (so the PR can confirm or correct them before it merges):
Two asks: the release number that will carry this PR (the flows' |
CSD/3 says a flow must be able to check what the UI SHOWS. This is the half that makes that true rather than specified. VENDORED, NOT REWRITTEN. `flow_spec.py` is 475 lines of stdlib plus yaml and names nothing of CIRISAgent's app shells, so unlike `platforms.py`'s bring-up it transplants whole. What it needs is an async helper; this repo's driver is synchronous, so `flow_helper.py` changes the tense and nothing else. Re-implementing the runner would give this repo a SECOND definition of what `visible` means, which is how a harness scrolls 300px of a 3142px form and reports success (#30). EXTENDED with the §3 predicates — `count`, `number`, `matches`, `one_of`, `each`, `relation`, `state`. Additive: every upstream spec still loads and behaves identically, so a re-sync is a diff against a known base rather than a merge of two designs. `relation` operands are CSD `ceg:` field ids resolved through the runner's `field_tags`, because the relationship is between VALUES and the meaning travels with the constitutional family — a UI rendering `capacity:composite` as an average misstates the Constitution rather than merely looking wrong. Two rules exist because their absence is a specific defect: `each` over a selector matching nothing FAILS rather than passing vacuously, and `count: {eq: 0}` is legal only alongside an explicit `state: empty`. Both are the empty-set trap — the shape that let this repo's own gate report "everything tagged is drivable" about a screen with no elements. EXERCISED AGAINST A RUNNING CLIENT, not just imported. `count` found 6 buttons and failed correctly against `eq: 999` naming the real count and the tags; `each` over a non-matching selector failed as required; `number` refused a button label rather than reading it as zero. AND THE FOUR CSD FLOWS RAN. Built a #45-carrying jar (that branch merged onto main, all four CSD tags present), flipped the local flow copies off `client: unreleased` — which is CSD/3's `sketched -> testable` transition — and executed all four. They report, correctly: [FAIL] requires: expected screen 'HealthReputation', on 'Login' on screen and drivable now: [btn_google_signin, btn_local_login, …] That is the standard's "this flow cannot start here" rather than "this element is broken" — different bugs with different owners, and the runner names the expected screen, the observed screen and the drivable set. Reaching those screens needs a node fixture, a session, and the sidebar nav hop, which the standard assigns to the runner and which lives outside flow_spec.py. A FIDELITY GAP, STATED RATHER THAN PAPERED OVER: the runner reads an element's `visible` flag and this client serves none, so `is_element_visible` falls back to geometry permanently. A composed element below the fold has non-zero size, so a `count:` glob on a long screen is an upper bound. `is_ghost` does not close it — that answers drivability, a different question. Closing it means the client serving the flag, which is a client change and not a shim's business to fake. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01SE8wgNWyEefkFthZo4Kwei
… fixture
Two of the three things a CSD flow needs before it can return a verdict.
THE HOP IS DERIVED, NOT TRANSCRIBED. FSD/CSD_STANDARD.md §5 puts the walk to a
flow's first screen in the RUNNER, so a sidebar reorder is one fix instead of one
per flow. That only holds if the runner can answer "where does Screen X live"
from the client's own tables, so `nav_map.py` reads them:
EpistemicSidebar.kt navTag(id) = "nav_epistemic_${id.replace('-','_')}"
group toggle = "nav_group_${group.id}"
EpistemicNav.kt surface ids, group membership, children
CIRISApp.kt NavSurface.<Name> -> Screen.<Screen>
A hand-written map would be a second source for a question the client already
answers, and it would drift the first time a surface changed group — silently,
because a wrong hop looks exactly like a screen that failed to compose.
54 screens resolve, including children through their parents: `Constitutional`
is `nav_group_commons-layers -> nav_epistemic_layer_global_commons ->
nav_epistemic_constitutional`, and clicking it directly would fail as "element
not found" on a sidebar whose parent had not expanded.
THE FIRST PARSER FOUND 15 OF 54 AND SAID NOTHING. It terminated on `\n\s*\)`,
and these declarations close with `,)` on the same line as their last argument —
so it silently skipped every surface written that way, including two of the four
the CSD flows need. The symptom was "no sidebar route", which reads as a nav gap
rather than a parser bug. Paren-balanced now, and guarded: a map under 40 screens
fails, and so does any hop that repeats a tag (the shape a fallback leaves when a
lookup returned nothing). Both were real outputs of the broken version.
THE NODE FIXTURE is what `.github/actions/ciris-node` does, available locally, so
a developer running a CSD flow does not hand-reproduce the two things that cost a
day: `--home` rather than an env var (the server reads none), and `/health` on
:4243 rather than the agent's `/v1/system/health` on :8080. It refuses to start
when something is already serving — the CIRISClient#52 family — and fails fast
when the process dies rather than burning its whole budget.
WHERE THIS GETS TO, run against a real node and a #45-carrying build: the hop
resolves the target, walks the chain, and stops with
CANNOT START — hop: 'nav_group_manage' would not click; on screen:
[btn_google_signin, btn_local_login, …]
which is correct and is the last mile: the sidebar does not exist on Login. The
remaining piece is a session — the node is fresh, so it is setup-then-login,
which is what CIRISAgent's `desktop-setup` does and what this fixture does not
yet.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SE8wgNWyEefkFthZo4Kwei
…f routes
The insight from building the runner, applied back to the standard: a CSD should
name its SURFACE and its FAMILIES, and let the tags and the hop fall out by rule.
`surface:` REPLACES v1's "reached from / leaves to" table. EpistemicSidebar
computes a surface's tag as `nav_epistemic_${id.replace('-','_')}` and a group's
as `nav_group_${group.id}`; EpistemicNav holds group membership and every child's
parent. So `nav_map.py` answers "where does this screen live" from the client
itself, and `constitutional` resolves to `nav_group_commons-layers ->
nav_epistemic_layer_global_commons -> nav_epistemic_constitutional` with nobody
typing that chain. A written route is a second source for a question the client
already answers, and it drifts the first time a surface changes group —
silently, because a wrong hop looks exactly like a screen that failed to compose.
The checker resolves `surface:` through the same map the runner walks, so a CSD
naming an unreachable surface fails at load rather than at 2am against a timeout,
and the CSD and the harness cannot disagree about where a screen is.
ALL FOUR UPLIFTED, and the stage machine immediately did its job by telling them
apart. CSD-001, -002 and -004 sit at `sketched` because their contracts are
`unconfirmed` — correct there, a failure at `building`. CSD-003's §3 IS answered
against ciris-server 0.5.199's route table, so its blocker is the `proposed:`
tags rather than the substrate. Same stage, different reasons, and the document
now says which.
What the CEG-as-identifier buys, per CSD:
004 the composite example is 0.68 — the lowest factor, NOT the mean of 0.784 —
so a rendering that averages is visibly wrong against the table, and
`relation: min_of` asserts it rather than trusting the reader.
003 `accord:*` is reserved `accord_holder-only` (CC 3.4.1), so display-only is
ENFORCED: this client cannot mint Accord state and an `emit` fails the
load. `one_of` on the killswitch so a third value cannot render as either.
001 outbound and inbound get different tags because #45's own history has a
cut that reported grants as authority — telling an owner someone has power
over them when the truth is the reverse.
002 `mesh_config:{key}` is NOT reserved, so display-only there is a choice
this CSD makes rather than one the registry forces. Worth the distinction.
THE CHECKER DISAGREED WITH THE STANDARD IT ENFORCES. `list[…]` is declared in
§2.1.1 and was missing from the checker's type vocabulary, so two correct CSDs
failed. That is the defect class this whole exercise is about, one level up: the
thing doing the checking had drifted from the thing being checked. Aligned, with
a guard that runs every CSD through it.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SE8wgNWyEefkFthZo4Kwei
… verdict
THE LAST PIECE. Every CSD surface lives in the sidebar, the sidebar does not
exist on Login, and a fresh node has no owner to log in as. The session has to be
MADE before it can be used.
DISCOVERED BY DRIVING IT. The sequence is what the client actually does on a
fresh node, observed through /tree rather than read out of the source:
Login (isFirstRun=true) -> btn_local_login
Setup, step `you` -> username/password/confirm/device, age band, next
Setup, `join_federation`-> consent toggles, next
setup_ownership_claimed -> no advance control; the claim is work, not a step
Login, now with txt_owner_hint
btn_local_login, credentials, btn_login_submit
-> Contacts, the node home
Two things a fixture written from the source would get wrong: on desktop,
first-run shows LOGIN and not Setup, so waiting for Screen.Setup waits forever;
and the claim step has no button, so polling for a control polls for something
that will never appear.
Isolation is two different flags, which is the distinction that cost a CI run
earlier today: the NODE takes `--home` (Server 0.5 reads no environment at all),
the CLIENT reads `CIRIS_HOME`. A throwaway run points each at its own directory.
THE HOP HAD A BUG THE FIRST RUN FOUND: a group toggle TOGGLES, so clicking it
unconditionally expanded the group for the first flow and collapsed it for the
next. Two surfaces sharing one gate behaved differently, which is what ruled out
substrate gating and pointed here. It now clicks a step only when what that step
reveals is not already on screen.
AND THEN THE LOOP CLOSED. Against a #45-carrying 0.5.218 build, a real
ciris-server 0.5.204 on its own home, and a real session, `capacity_attestations`
reached HealthReputation and returned:
[FAIL] expect: 'federation_capacity_live' is not on screen
which is CORRECT, and is the flow doing exactly what its description says it is
for. `card_federation_capacity_attestations` was present; the live marker was
not, because the node was fresh. "A gate placeholder would satisfy the card tag
alone" — the flow distinguished a rendered card from live data on the first run
that could reach the screen.
WHAT RUNNING IT TAUGHT THE SPEC, which is the whole point of the lifecycle:
* the five factors ship as factor_row_{c,i_int,r,i_inc,s} — the CEG families by
symbol — and the composite as card_capacity_composite. CSD-004's proposed
tags were wrong, and are now the real ones.
* `federation_capacity_warming_up` exists and nobody had written it down. A
real fifth state, recorded as `empty` because that is what it means.
* `error` is still the gap that matters: a fresh node produces warming_up and
a failed read produces nothing distinguishable from it, so the mission's own
"we could not ask" versus "nothing has happened" is not yet expressible.
That last one is a finding for #45 rather than a fix here.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SE8wgNWyEefkFthZo4Kwei
# Conflicts: # client/VENDORING.md
…ha) read the hairline token Main gained the colour-literal ratchet while this branch waited; after the merge it reported 4 new literals in HealthReputationScreen and ConstitutionalScreen — every one a border or a track drawn as white at 4–8%, which is exactly what `CirisTheme.tokens.hairline` and `sunken` are. Read the tokens; the lint is green again and the digest re-recorded. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01Xv1s8qrUoPoFX2MHZUPA15
|
Brought up to date with
🤖 Generated with Claude Code |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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