π release(staging β master): bilateral drawer and contribution, developers section, geography/MDS fixes, table resize-sort fix - #764
Merged
Conversation
β¦nd show the three USD tables together
Nicoleta Trifa, after a round of manual W3/bilateral testing (Freshservice #INC-163204, point 4).
Distributed by Juan Carlos Cadavid through Santiago SΓ‘nchez on 21-Sep-2026. Two of the four
sub-points; (b) and (d) are deliberately not in this commit, see below.
AC1 β the use level is no longer a minimum data standard ("the use levels are not part of the MDS
- pls remove"), reversing part of P2-3428. Removed in BOTH places that enforced it, because either
one alone produces a contradiction the reporter cannot act on: the form's tracker (a client-only
relaxation turns a blocked section into a green section whose Submit is still refused) and the
server gate, which answers `submit-for-review` AND `POST /api/bilateral/create` (a server-only
relaxation leaves the form still demanding it). The question stays on screen and is still stored
and returned β only the demand is gone, and it keeps driving the three questions below it. No
stored result becomes invalid: this validator only ever refused, it never wrote.
AC3 β the USD estimation shows its three destinations at once ("needs to have 3 fields: one for
the Program..., one for the bilateral project, one for the listed external partners"). All three
already existed since P2-3390, but Programs and Partners were rendered under the "Complete full
metadata" toggle, so a reporter who never opened it saw one of the three amounts they were asked
for. The three tables now render together above the toggle and the duplicate block below it is
gone β two `app-estimates-cgiar` bound to the same `body` would have drawn every row twice. Only
the W3/bilateral table stays required: investment is outside the green check by PO decision
(9-Sep-2026), and making the other two mandatory would have silently turned optional data into a
submit blocker.
Verified against the fix landed earlier today in 146d261: `reconcileInvestmentTables` already
re-reads all three arrays on entering the section, so the two tables promoted here inherit that
refresh instead of going stale β they were previously the ones most likely to.
Not in this commit, and why:
- (b) gender/youth "set-up as for pooled" is blocked on a data decision. The bilateral form asks
"Sex and age disaggregated data available?" and stores `true` when the answer is YES, while the
rest of the platform reads that same `result_actors.sex_and_age_disaggregation` column with the
OPPOSITE meaning β pooled asks "Sex and age disaggregation does not apply"
(`innovation-use-form.component.html:127`) and the validation SQL takes `= 0` as the branch that
requires women/men and `= 1` as the branch that requires only `how_many`
(`results-innovation-packages-validation-module.repository.ts:372-391`). Aligning the form with
pooled therefore inverts what the column means for every bilateral actor already stored, in
production since 18-Sep, and needs a backfill decision that is not ours to take.
- (d) the reporter's wording and the team's summary state opposite intents, and the symptom
described matches the defect fixed today in 146d261 β it needs re-testing on this build before
any code is written for it.
Tests: the two gates now carry their own locks, both verified to fail when the old rule is put
back. Server: tsc clean, 847 tests across 37 suites in api/bilateral, eslint clean on the files
touched. Client: 1760 tests across 52 suites in pages/bilateral.
π NOT PUSHED: `npm run build:dev` β the only thing that typechecks Angular templates, and this
commit edits one β has not been run. 1.04 GB of RAM available at commit time, below the floor for
a build on this machine.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ram out of the contributing dropdown The Innovation Package Contributors form offered the package's OWN Science Program as a contributing one. Picking it answered 201 with a success toast and the chip was gone on reload, because the server drops the owner without reporting it: `createTocMappingV2` runs `pendingIds.filter(id => id !== initSubmitter.initiative_id)` (results-toc-results.service.ts:1596) and `resultRequest` refuses to share a result with its own owner (share-result-request.service.ts:183). Reproduced on result 9409 (owner SP01): the PATCH carried pending=[50, 51] and only 51 came back. Verified on screen after the fix β searching "Breeding" in the dropdown now returns nothing, while SP02 and SP03 stay selectable. Both sibling forms already exclude the owner and this one lost the filter in the P25 migration: rd-contributors-and-partners.component.ts:728 and ipsr-contributors-toc.component.ts:38. The list is recomputed only when the catalog or the owner lands, never in a template getter: handing app-pr-multi-select a new array on every change-detection pass is one of the two NG0103 loop conditions for that control. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ugh the shared token enum QA found the result-detail rail painting `Quality Assessed` with the APPROVED green while the Results Center table one click away painted it cyan, and `Approved` falling through to the grey "unknown status" fallback because the rail's private map had no entry for it (Cami, Slack video, 21-Sep). Five surfaces each carried their own copy of the status palette and they disagreed on Editing, Pending review and Draft as well. `result-status-tokens.ts` becomes the one place: it now carries the canonical LABEL per status id alongside the fg/bg pair, and accepts the `string | number` the detail endpoint actually answers, so no caller has a reason to coerce and re-map on its own. The result-detail rail, the bilateral page header, the Review External Result drawer, the bilateral results list, the drafts list and the Results Center table all resolve through it. Pending review moves off grey onto the Submitted pair: grey reads as "inactive / disabled" on a result that is mid-flight, and it sits on the same rung of the flow as Submitted does for W1/W2. Editing's amber was ruled out because both statuses share a column in the Results Center, where two identical chips would mean opposite things. No seventh colour was invented (UI-RULES rule 9). Also removes a trailing SCSS override in the Results Center that repainted Approved and Rejected with the legacy PRMS green and red while keeping the token background β half of one pair on half of another, which is exactly what rule 9 forbids. One existing test had the defect frozen into it (it demanded the approved green for Quality Assessed) and was corrected; six lock tests were added so a future private map cannot pass by looking neutral. Gate: client `npm run build:dev` green, `ng lint` clean, 597/597 suites and 11110 tests passing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦rmance-refactor
β¦s in capacity sharing drawer
β¦sleeping 600ms Jenkins build #2354 went red on this single assertion while the same test passed three times in a row locally, and a red build blocks prtest for the whole team. copyTable clears flatFormat through two NESTED 200ms setTimeouts, so the fixed wait(600) left only 200ms of slack: enough on a laptop, not on a CI agent running 597 suites. The wait is now a poll on the rendered class with a 5s deadline. The guard keeps its teeth: with the repaint blocked the deadline runs out and the assertions fail, verified before committing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ry and description in the setup drawer [SPEC:quick/bilateral-drawer-project-details] The creation flow moved into the Set up bilateral result drawer, and that drawer only rendered an unlabelled snippet (summary || description) clamped to two lines, so AC2/AC3 could not be verified anywhere in the live flow. The drawer now renders one labelled read-only block per field, and only for the fields CLARISA actually filled: 2026 projects mostly arrive with summary null and the text in description, and either field can come back as an empty string rather than null. When neither exists an explicit empty state says so, which keeps no data distinguishable from the field is missing. Long text keeps the two-line clamp behind a Read more toggle, since the drawer is now the only place this text is readable. Normalisation and de-duplication live in BilateralManualCreateFlowService, so the drawer receives text that is already trimmed and free of values that merely repeat the project title or the other field. Verified: jest --testPathPattern=pages/bilateral 70 suites / 2344 tests pass, ng lint clean. Triviality gate for akili-quick did not pass (conditional render, toggle state and data normalisation across three components); fast-tracked on explicit instruction and recorded as such in the quick log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦percentage to the bilateral Project Information P2-3352 section 6 specifies a Contribution field (numeric + %, default 100, editable only while the result is in Editing) in Section 1 of the W3/Bilateral form. It rendered nowhere, and there was nowhere to store it either: results_by_projects carried only is_lead. Server: additive nullable decimal(5,2) column, entity, an optional 0-100 DTO field, and the four write branches of PATCH primary-assignment. Omitting the key leaves the stored value untouched, so an older client cannot blank it; NULL means never answered and reads back as the 100 default. Client: the field renders through app-pr-input inside the existing project block, read-only once the result leaves Editing, and rides the section save. The save button now names what it saves instead of always promising a project and program change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦s the primary reference [SPEC:quick/developers-official-docs] The right-column card promised the full field reference and sent the reader to the Swagger UI of the ingest API. The authoritative reference is the public Notion page PRMS Normalizer - Technical Field Documentation, which is where the field rules, the minimum data standards, the CLARISA catalogues and the breaking changes log actually live; Swagger only lists request and response shapes and lets you fire a test call. The card is now Official documentation: Notion is the primary CTA, Swagger stays as a secondary link under a divider, and the copy states which one wins when the two disagree. Step 2 of How to integrate was renamed to match. The page also notes that Notion needs no account, since the route itself is behind CheckLoginGuard and the integrator reading this may have no PRMS session. Verified public without login before linking it: publicAccessRole reader, requireLogin false. officialDocsUrl is hardcoded next to the six API Gateway URLs already in the component rather than read from environment.ts, because this page lists test and production side by side and is a reference table, not the current environment. Verified: scoped ng lint on the pages ts and html clean, jest developers 10/10 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦lves [SPEC:quick/developers-prod-bulk-host] The production bulk ingest row carried b1a4fsvgni with the digit one. That host has no DNS record: curl answers Could not resolve host. The live gateway is bla4fsvgni with the letter l, which answers 401 Missing x-api-key. The two are indistinguishable by eye in a proportional font, so a spec assertion now locks the working one in and rejects the other. Two smaller corrections found while verifying the endpoints against the published OpenAPI document, v1.2.0 and identical on both gateways: The Set up webhooks button carried a #/Webhooks fragment. The document declares no tags, so swagger-ui groups every operation as default and renders no such section: the anchor resolved to nothing. Dropped it, and named the two operations in the copy instead, since POST /webhook registers the destination and GET /webhook reads it back. Both doc buttons open the test gateway and did not say so. The page stays deliberately NOT environment-aware, per explicit decision: it is a reference that lists every environment at once rather than a view of the one serving it, so somebody on test may well want to follow the production link. That only works if each link states which environment it opens, so the copy now does, and the production Swagger stays one card below in Environments. Endpoints were probed read-only, GET only, never POST. Verified: scoped ng lint on the pages ts and html clean, jest developers 12/12 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ form, not only an admin A Center User of the result's lead centre could open a W3/Bilateral result in Editing and not find a single control: every custom-field renders its value as plain text while the GLOBAL RolesService.readOnly flag is up (pr-multi-select.component.html:16, and the same line in pr-input, pr-select, pr-textarea). That flag is a W1/W2 mechanism β it starts TRUE for anyone who is not an application admin (roles.service.ts:75) and is only lowered when a W1/W2 result is loaded for a member of its INITIATIVE (current-result.service.ts:52), a path bilateral never walks. In practice only admins could edit a bilateral result, which no requirement asks for. Measured on prtest result 9553 with the reporter's real roles: 6 app-pr-input hosts, 0 <input>. The editor now answers that flag with the question the server already asks before accepting a write β Center User (role 9) on the lead centre's CLARISA code, as validationCenterPermissions does β combined with the existing status gate, and restores the application default on destroy so the permission never leaks into a W1/W2 screen. RolesService gains a rolesVersion counter: `roles` is a plain property, so a computed derived from getMyCenters() cached the empty list it saw before the roles GET resolved and would have left a legitimate Center User locked out for the whole visit on a cold start. Verified in a real browser against prtest with that user's roles injected β locked before, 7 editable fields after β with the negative control of a Center User of a different centre, which stays read-only exactly as the server's 403 would. Client suite 11143 tests and build:dev pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ry and description in the setup drawer [SPEC:quick/bilateral-drawer-project-details] The creation flow moved into the Set up bilateral result drawer, and that drawer only rendered an unlabelled snippet (summary || description) clamped to two lines, so AC2/AC3 could not be verified anywhere in the live flow. The drawer now renders one labelled read-only block per field, and only for the fields CLARISA actually filled: 2026 projects mostly arrive with summary null and the text in description, and either field can come back as an empty string rather than null. When neither exists an explicit empty state says so, which keeps no data distinguishable from the field is missing. Long text keeps the two-line clamp behind a Read more toggle, since the drawer is now the only place this text is readable. Normalisation and de-duplication live in BilateralManualCreateFlowService, so the drawer receives text that is already trimmed and free of values that merely repeat the project title or the other field. Verified: jest --testPathPattern=pages/bilateral 70 suites / 2344 tests pass, ng lint clean. Triviality gate for akili-quick did not pass (conditional render, toggle state and data normalisation across three components); fast-tracked on explicit instruction and recorded as such in the quick log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦uzman-io/analyze-bilateral-api-docs
β¦uzman-io/analyze-bilateral-api-docs # Conflicts: # docs/specs/quick/quick-log.md
β¦General Information UAT return from Cristian (bilateral result 9180): Contributors & Partners, Geographic Location and Evidence show the standard MDS note at the top, but General Information still did not. The 2026-08-18 fix had moved it up. The 2026-09-04 style change (9f4cc79) moved the banner + Full metadata toggle below the MDS fields, and the note travelled down with it because here β unlike Contributors β the note and the button shared a single container. Split into two blocks, as Contributors already had them: the standard MDS note at the top of the section, and the "fields above" banner with the Complete full metadata button left untouched below the fields. [SPEC:quick/bilateral-mds-note-general-info] Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦rchive spec and record kaizen entry Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
β¦-only once a result leaves Editing Both app-sub-geoscope instances (main scope and extra scope) were wired to a hard [readOnly]="false" since a3a7156, so a result in Pending Review, Approved or Rejected still offered the country delete icon, the sub-national picker and the per-entry remove icon. The autosave refuses every write in that state (P2-3520), so the screen was offering edits that could never persist: remove an entry, reload, and it is still there. The component already honours readOnly - the binding was the defect, not the component. The new spec asserts on the markup rather than on a rendered fixture, because the sibling spec stubs the template with overrideTemplate and is blind to this class of defect - the same hole that let it through in section-contributors. Negative control run: reintroducing the literal turns 3 of its 4 cases red. Scope note for the ticket: the two controls named in the report - the region chips and the countries Yes/No - do NOT reproduce on prtest today. Measured on result 9464 (AfricaRice, Pending Review, status 5): 0 clickable multi-select triggers, the Yes choice ignores the click, and no PATCH or POST leaves the page. What was found instead is this sibling hole in the same section, fixed here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦k like the API one The Official documentation card ends in an inline violet text link to the test Swagger, while the Result decision webhooks card used an outlined button for the same kind of action. Both open the same Swagger, so they now share the link styling. The surrounding copy said the button opens the test Swagger and no longer would, so it now reads the same way as the other card. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
β¦ot the text link Corrects the direction of 2780a3d: the webhooks action was the reference design, so the Swagger action in the Official documentation card now matches it instead of the other way round. Both open a Swagger and both are outlined buttons. Copy follows: the documentation card says the button below opens the test environment, and the webhooks card goes back to saying the button opens the test Swagger. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dragging a column resize handle and releasing the mouse over the header cell (not back over the thin resizer strip) made the browser synthesize a native click on the <th>, which PrSortableColumnDirective and validateOrder() both read as a sort request. onResizeStart now registers a capture-phase, one-shot click guard on document for the duration of a resize drag so that phantom click is swallowed before it reaches either listener, with cleanup on mouseup/ngOnDestroy so a later, unrelated click is never affected. Verified: new regression test is red on the unmodified component and green with the fix; confirmed against the real running app (not just jsdom) by driving the exact mousedown/mousemove/mouseup/click sequence on the live <th> and observing the guard prevent it. Spec: docs/specs/bugfix/results-center-title-resize-triggers-sort/ Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
β¦ment-2026-mc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
β¦cted tables Extends bugfix/results-center-title-resize-triggers-sort beyond the Results Center table it originally covered. The same phantom-click mechanism (dragging a column resizer and releasing over the header synthesizes a native click that the header's sort listener reads as a sort request) is independently duplicated β copy-pasted, not shared β in three other tables, confirmed by reading each one's resize block in full: - programme-results.component.ts (Programme Results) - bilateral-results-list.component.ts (Bilateral centre results) - portfolio-overview.component.ts (Portfolio Overview matrix β adapted to its inline-closure onResizeStart and its sortBy(column) click binding instead of PrSortableColumnDirective) Each gets the same capture-phase, one-shot document click guard, matching that file's existing style. Also confirmed, and recorded as explicitly out of scope, that links-to-results-global.component.ts and both mapped-results-modal.component.ts files have no resize handle at all (grep for mousedown/resize: zero hits) β they only share the unrelated validateOrder sort helper, so no fix is needed there. Verified: one new regression test per fixed file, each red on the unmodified component (confirmed via git stash) and green with the fix. Full targeted suite: 220/220 passing. ng lint: clean. Spec updated: docs/specs/bugfix/results-center-title-resize-triggers-sort/ (Premise Ledger P-4..P-8, RCR-R-4/AC-3, RCR-DD-2, RCR-T-2..T-4) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
β¦es from qa-development-2026-mc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
| * assertions below forbid, and a comment is not markup. Without this the spec fails on its own | ||
| * explanation β which is a false alarm, and a spec that cries wolf gets deleted. | ||
| */ | ||
| const template = rawTemplate.replace(/<!--[\s\S]*?-->/g, ''); |
Cristian45
approved these changes
Sep 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Summary
bugfix/bilateral-section-autosave-on-navigate27 commits, 81 files (+2925 / β225).
stagingmerges intomasterwith no conflicts.Test plan
stagingmerges intomasterwith no conflicts (checked withgit merge-tree)π€ Generated with Claude Code