chore: release v16.2.0 - #1096
Open
kavin-114 wants to merge 43 commits into
Open
Conversation
…6.2.0 Backport of 44869a7 from develop without .mergify.yml (Mergify reads its config from the default branch only). Sets __version__ to 16.2.0 so the first release PR from version-16-hotfix carries the version it ships; the 12 backports merged since v16.1.0 include feature work, hence minor. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
…e tests Review of #1089 found two gaps. GitHub sends `pull_request.edited` when a PR's base is changed, and ci.yml ignores that event, so a PR opened against develop (guard trivially green) and then retargeted to version-16 would keep its stale pass. The guard now lives in release-guard.yml, which also runs on `edited` without dragging the test matrix along, and it rejects heads from a fork even if the branch is named version-N-hotfix. test_release_notice hard-coded 0.0.2 / 0.0.3 as "newer than installed", which only holds while __version__ is 0.0.1. The hotfix PRs bump it to 16.2.0 / 15.2.0 and three tests flipped. The tests now derive their newer versions from the installed one. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
… one Same failure class as test_release_notice: a literal 0.0.2 is only "newer" while __version__ is 0.0.1. The helper moves to jarvis/tests/_release_versions so both files share it. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
Review of #1091 (six-lane panel) found the guard head-controlled: a PR whose head predates release-guard.yml, or a fork that deletes it, gets no check at all rather than a red one. The workflow now triggers on pull_request_target so the BASE branch's copy runs; nothing is checked out and no head code executes, so the usual pull_request_target hazard does not apply. Release PRs (base version-N, head version-N-hotfix) additionally fail unless __version__ increased and its major matches the line. A release shipped without the bump would leave every bench on it stuck behind the control plane's release notice. Wording in the workflow header and CONTRIBUTING.md no longer asserts an enforcement the rulesets do not yet provide: the check blocks a merge only once it is listed as required in repo settings. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
…versions Follow-ups from the #1089 and #1090 panel reviews. ci.yml now listens to `pull_request.edited`, but every job carries `if: action != 'edited' || changes.base != null`, so a PR retargeted from develop to version-16-hotfix re-runs against the branch it will land on while a title or body edit does not burn the matrix. release-guard.yml: a concurrency group so repeated edits supersede each other, separate messages for a fork head and a wrong branch, and the `version-[0-9]*` glob so it only fires on the numbered lines. Tests: the derived-version helper is gone. A fixed far-future sentinel (99.0.0) reads as newer on every line without going through the parser under test, and _version now has its own edge-case tests (short and long forms, non-numeric, rc suffix, None) plus a check that an unparseable installed version never lifts the notice. PR template drops the stale "branch protection is not enforced on Free" note and adds the release-PR line. pre-commit comment likewise. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
Live test of the previous commit: a PR body edit produced an all-skipped ci.yml run that shared the concurrency group with the in-flight run and cancelled it on all three PRs. The deeper problem: a skipped job still posts a "skipped" check on the head commit, GitHub reads the latest check per name, and skipped satisfies a required check, so a title edit after a red run would have masked the failure. ci.yml is back to the default PR event types. The retarget case moves to release-guard.yml: an `edited` event carrying `changes.base` fails the job with an instruction to push or close/reopen, both of which make ci.yml run against the new base and re-run the guard. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
ci: adopt version-16-hotfix; stable only takes release PRs; bump to 16.2.0
…tools-version-16 fix(chat): hide agent built-in tools from the activity view (backport #1071)
4 tasks
…ch moves Under the hotfix model the only push to version-N is the release PR, and release-guard.yml already refuses it without a __version__ bump. So the Release workflow reads __version__ from the pushed commit, tags the merge commit vN.x.y, and publishes a Release with notes generated from the previous tag on the same line. Latest goes only to the highest version-N branch. Idempotent: an existing tag is a no-op, so a failed run can be re-run via workflow_dispatch. Needs the GitHub Actions app (Integration 15368) as a bypass actor on the "Release tags" ruleset, otherwise the tag push is refused. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
…heck Review of #1098: the early "tag exists" exit meant a run that pushed the tag and then failed on `gh release create` could never be repaired by a re-run. Tag and Release are now checked separately, so a re-run publishes the missing Release (and the previous-tag lookup excludes the tag being released). The branch check is an anchored regex instead of a glob, so `version-16-hotfix` under workflow_dispatch gets the right error. Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
…llows
GitHub rejects the built-in Actions app as a ruleset bypass actor
("must be part of the ruleset source or owner organization"), so the
"Release tags" ruleset dropped its `creation` rule instead and keeps
deletion, update and the name pattern. The header said otherwise.
Claude-Session: https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6
…ion-16 ci: release automation (backport to version-16-hotfix)
fix(desk-nudge): match the CTA to the actual readiness reason (cherry picked from commit dbcb0d4) Claude-Session: https://claude.ai/code/session_01HW2uHdQLPLoV8qVXm6Ppxu
feat(support): move the waiting-reply signal to a header count pill (cherry picked from commit ab8892a) Claude-Session: https://claude.ai/code/session_01HW2uHdQLPLoV8qVXm6Ppxu
feat(schedule): add a weekday and day-of-month picker to agent and macro schedules (cherry picked from commit b7b6cd8) Claude-Session: https://claude.ai/code/session_01HW2uHdQLPLoV8qVXm6Ppxu
…sion-16 backport(v16): fix(desk-nudge): match the CTA to the actual readiness reason (#1102)
…l-version-16 backport(v16): feat(support): move the waiting-reply signal to a header count pill (#1103)
…absent here jarvis/tests/_agent_access.py landed with the deny-by-default agent access gate (#1062), which this line does not carry, so the backported install test failed with ModuleNotFoundError on CI shard 2. Grant the Jarvis User role on the close-auditor listing directly for the test's duration and remove only the row it added. Claude-Session: https://claude.ai/code/session_01HW2uHdQLPLoV8qVXm6Ppxu
…r-version-16 backport(v16): feat(schedule): add a weekday and day-of-month picker to agent and macro schedules (#1104)
fix: Force Resync reconciles proxy sidecars for pool tenants (cherry picked from commit f3de3fb)
…ars-version-16 backport: Force Resync reconciles proxy sidecars for pool tenants (#1111)
…ing sections) Collect a complete billing address / place of supply on the onboarding Details step so the post-payment GST invoice can be raised correctly. - Two sections: Company Details and Invoicing Details. The invoice is raised to the Invoicing Details party; a blank invoicing company/email falls back to the customer's own company + work email, and the defaults mirror the chosen company/email until the customer overrides them. - Full address shape mirroring ERPNext's Address: Address line 1, line 2, City/Town, Postal Code, State, Country, GSTIN. - Required for a valid place of supply: contact number, Address line 1, City/Town, Postal Code, State and Country. Country defaults to India in the field VALUE (was only displayed, so an untouched form submitted an empty country) at source 'empty' so an ERP default / resume still wins. State is a validated Indian-state select for India, a required free-text region otherwise. - Layout: Country left / State right at equal width (select triggers forced full-width); Contact number paired with Invoicing email. - Provenance-aware billing model (useBillingDetails) with ERP-default fencing, namespaced localStorage resume, and a byte-identical control-plane contract fixture. Full frontend suite green. (cherry picked from commit 3f97775)
… (C1) Sub-project C1 (admin usage dashboard, tenant Usage tab): pushes the new data the admin dashboard needs, no customer-facing UI change. - Jarvis Chat Session gains context_capacity (Int) and context_pct (Percent). usage.record_turn_usage and refresh_session_snapshots now store the gateway's contextTokens (capacity) alongside the existing totalTokens (used) snapshot, and compute pct = round(100*used/capacity, 1). - usage_push._build_rollup adds schema_version: 2, a per-user context block (used_max, capacity, pct_max, sessions_over_80, last_seen_at, sourced from Jarvis Chat Session), and a top-level users_daily list (from Jarvis Turn Usage, grouped by user/day/model, last 35 days including today, 5000-row cap trimming lowest-token rows first, per_model capped at 20, email lowercased). The old shape and the existing truncation warning are unchanged; context/users_daily are additive and degrade to null/empty when there is no session or turn data, never fabricated. - api_errors.collect_error_log now sets user_ref from the Error Log row's owner when it names a real user (not Administrator/Guest), so code-level exceptions get the same per-user attribution UI errors already carry. Tests extend the existing usage/usage_push/api_errors suites: builder shape, old-shape compat, users_daily window/grouping/per-model cap, row-cap trimming (pure-function unit test, no bulk DB seeding), and user_ref attribution for both a real owner and Administrator/Guest. Claude-Session: https://claude.ai/code/session_014XnuuU2sGmbjwUzWim7xM9 (cherry picked from commit 554a9b9)
1. refresh_session_snapshots no longer overwrites context_capacity/
context_pct with 0 when a sweep row carries no contextTokens - written
only when the row reports capacity > 0, stored values kept otherwise.
2. usage_push._context_by_user no longer pairs one session's used_max with
a different session's capacity. pct is now computed per session (used/
capacity of that same row); the session with the highest own pct wins
and reports its used/capacity/pct as used_max/capacity/pct_max;
sessions_over_80 counts sessions whose own pct >= 80; last_seen_at is
unchanged (newest last_usage_at across all sessions).
3. refresh_session_snapshots folds its two near-duplicate UPDATEs into one:
last_usage_at = COALESCE(row's updatedAt, stored last_usage_at, now),
modified always advances. Uses the Python-side `now` already computed
per sweep (not SQL NOW()), since NOW() is DB-session-timezone and only
second precision - neither reliable for the ordering this fix exists for.
4. record_turn_usage's VALID_ZERO path now refreshes context_capacity,
context_pct and last_usage_at too (previously only RECORDED did),
through the same never-clobber-with-0 guard as item 1.
5. usage_push._build_rollup now lowercases users[].email, matching
users_daily and admin's own lowercasing on ingest.
6. usage_push._iso_utc_z reuses a module-level ZoneInfo("UTC") instead of
constructing one per call.
The stored context_pct column is unchanged (sub-project B reads it).
One test per item, extending jarvis/tests/test_turn_usage.py.
Claude-Session: https://claude.ai/code/session_014XnuuU2sGmbjwUzWim7xM9
(cherry picked from commit 0eb7ecd)
Hosted CI caught it: test_user_settings.TestAdminSync. test_refreshes_snapshots_without_accumulating asserts last_usage_at stays None after a sweep row with no updatedAt - last_usage_at means "last real usage", so stamping sync time would make admin's "last seen" wrong. Drop the now()/`now` fallback from the folded UPDATE's COALESCE: a row with no updatedAt now leaves last_usage_at exactly as it was (None if never set, unchanged otherwise). modified still advances on every sweep via the same %(now)s param, so "just synced" stays orderable independent of last_usage_at. Adjusted test_refresh_session_snapshots_stamps_last_usage_at_without_updated_at to assert last_usage_at is unaffected by a no-updatedAt sweep (both from None, and once a real stamp already exists) while modified still advances. Claude-Session: https://claude.ai/code/session_014XnuuU2sGmbjwUzWim7xM9 (cherry picked from commit 2f28cd0)
…#1127) Backport of the develop merge e7f4a7c onto version-16-hotfix. The hotfix lines still derive the soft worker warning from the F1 starvation shape (_pump_shape_starves), so chat_worker_status keeps that and only the hard block and its zero-marker machinery are removed; the total-headcount warning from develop is not part of this backport. (cherry picked from commit e7f4a7c) Claude-Session: https://claude.ai/code/session_01WSDfCaikikyY9jq3BhDvYz
feat(onboarding): collect billing State + Country for India Compliance (backport #1080)
…1124 feat(usage): per-user daily buckets and context fullness in the usage push (backport #1124)
…1127 fix(chat): never refuse a send on a stale RQ worker registry (backport #1127)
…details Add two cards to the customer billing page: - Billing details: an editable GST billing party (contact person/number, address, city, pincode, state [Select of GST states for India], country, GSTIN) plus the email invoices are sent to, for a direct customer. A partner-billed (reseller) customer instead sees a read-only "billed through <partner>" notice — their invoice party is the partner's, managed by them. - Invoices: the customer's own submitted GST invoices with a per-row PDF download, plus loading/empty/error states. Wiring is the standard tenant->control-plane bridge: api.js -> jarvis.account.* (require_jarvis_admin + _surface) -> admin_client._post -> control-plane api.invoices.* (current_customer-scoped). All ownership scoping, the partner margin-leak exclusion, and GSTIN/state validation are enforced control-plane side; the frontend only renders and edits what it is allowed to see. (cherry picked from commit a879a61)
…the customer) get_billing_profile now always returns bill_to "customer", so the read-only partner notice can never render. The billing-details card is always the customer's own editable GST party. Pairs with the control-plane change that always bills the end customer. (cherry picked from commit 477ccca)
The billing-details card is now "Invoicing details" and captures the party the GST invoice is raised to: Invoicing Company Name + Invoicing Email (optional — blank falls back to the customer's own company name + account email), alongside the existing address / GSTIN. Pairs with the control-plane billing_company_name / billing_email fields. (cherry picked from commit bb181ae)
develop enabled require_type_annotated_api_methods (hooks.py), which 500s a whitelisted method with an un-annotated parameter on a strict bench. The billing-portal branch predates that rule, so its jarvis.account.update_billing_details had a bare `billing` param. Annotate it `dict | None` (matching the sibling jarvis.onboarding.update_billing), fixing the test_whitelist_annotations guard. (cherry picked from commit 12cb033)
…leteness gaps Addresses a review of the billing State+Country work (#1080): several paths could omit required address data or submit an invalid country, and unsupported countries failed post-payment invoice creation. - P1: the country dropdown ended in a literal "Other", submitted as-is to the Frappe Address.country Link where no such Country exists → invoice creation failed after payment. Replace the curated list + "Other" with the full 250 Frappe standard countries (India + the sold-into markets first, then alphabetical); every option is now a real Country. Books still distinguish only India (domestic) vs Overseas. - Hydrate address2 + pincode in both the ERP-defaults and server-summary converters, so defaults / recovery prefill the now-required postal code instead of leaving it blank or stale. - Persist the mirrored invoicing default when syncInvoicingDefaults changes it: setIdentity persists BEFORE the watcher runs it, so a reload kept the new identity beside a one-keystroke-stale invoicing recipient. - Guard billing completeness on the resumed Pay path: extract billingDetailsInvalid() and run it in onPayClick, so a session landing directly on Review & Pay can't submit without address/city/state/pincode (a missing state also blocks signup once place-of-supply charging is on). - Clear a stale state/region on a real country change, so an Indian state left selected after switching country can't make "United States / Tamil Nadu" pass validation. Tests: new indianStates.spec + additions to useBillingDetails.spec and OnboardingView.spec; a localStorage-isolation fix to the shared beforeEach that surfaced a fragile pre-existing onPayClick test. Full frontend suite green, prettier v2.7.1 clean. (cherry picked from commit be2eecf) # Conflicts: # frontend/src/views/OnboardingView.spec.js
…; persist invoicing provenance Second review pass on the billing address fixes: - P1: restored snapshots and ERP defaults bypass the country select, and countryError only checked for non-blank. A pre-change "Other" or a legacy "Turkey" (this list carries the renamed "Türkiye") therefore passed validation yet failed the Address.country Link after payment. Add canonicalCountry() (alias map + case-insensitive match) and isValidCountry(); countryError now rejects a value not in COUNTRIES, and the defaults/summary converters + restore + buildBilling canonicalise the country — so an alias auto-corrects and a genuine unknown is rejected, never submitted. - P2: persisting the mirrored invoicing default (previous pass) stored it WITHOUT provenance, so restore() marked every auto-mirrored value as a user override and stopped tracking — a later company/email change then submitted the stale (possibly site-admin) party. Persist invoice_*_user_set and restore it (legacy snapshots with no flag default to user-set, preserving prior behaviour). Tests: canonicalCountry/isValidCountry; country canonicalised from restore, ERP defaults and buildBilling; countryError rejection; invoicing provenance survives a reload (auto keeps tracking, override stays fixed, legacy treated as override). Full frontend suite green, prettier v2.7.1 clean. (cherry picked from commit 573e440) # Conflicts: # frontend/src/views/OnboardingView.spec.js
…1081 feat(billing): customer billing portal — invoices + editable billing details (backport #1081)
…1131 fix(onboarding): capture a valid billing country + close address completeness gaps (backport #1131)
Reject a billing address whose State, postal code and GSTIN state code disagree before it reaches invoicing — e.g. State=Maharashtra with a Tamil-Nadu PIN would otherwise book the wrong GST place of supply. SPA mirror of the jarvis_admin_v2 control-plane authority: a shared State↔PIN-prefix↔GST-code table (address.js) drives a live on-blur check on the Details step (the postal code's first 3 digits and the GSTIN's state code must agree with the selected state); the plane re-validates on signup, so the SPA is never the only guard. Byte-parity with jarvis_admin_v2 + India Compliance verified. Tests: address.test.js (11, node --test) + OnboardingView.spec (82, vitest). (cherry picked from commit 332b552) # Conflicts: # frontend/src/views/OnboardingView.spec.js
…6 backport version-16-hotfix has no OnboardingView.spec.js of its own — the mergify backport pulled in develop's ENTIRE spec (1710 lines), whose "post-checkout settling hold" tests exercise develop-only payment-recovery behavior the version-16 component doesn't implement (9 failures). The address-consistency logic is fully covered by the pure address.test.js (node --test); keep that + the OnboardingView.vue wiring, and don't introduce develop's whole component spec onto a divergent branch.
…1137 feat(onboarding): validate State ↔ Pincode ↔ GSTIN address consistency (backport #1137)
feat(chat): context meter and Compact with hint (cherry picked from commit 7a7c2fd)
feat(chat): context meter and Compact with hint (backport #1136)
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
First release cut under the hotfix model: merges
version-16-hotfixintoversion-16and ships as v16.2.0. Sites on the v16 line get every backport merged since v16.1.0 and start reporting a real version (bench versionreads 16.2.0 instead of 0.0.1).Backports in this PR (version-16-hotfix, newest last):
__version__16.2.0Already on
version-16since v16.1.0 (in the release notes, not in this diff): #1075, #1074, #1069, #1066, #998.After merge the
Releaseworkflow (on this branch via #1099) tags the merge commitv16.2.0and publishes the GitHub Release with generated notes from v16.1.0. Merge with a merge commit only.Pre-merge checklist
version-N: this is the release PR fromversion-N-hotfix,__version__is bumped, andrelease-sourceis greenhttps://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6