Skip to content

chore: release v16.2.0 - #1096

Open
kavin-114 wants to merge 43 commits into
version-16from
version-16-hotfix
Open

chore: release v16.2.0#1096
kavin-114 wants to merge 43 commits into
version-16from
version-16-hotfix

Conversation

@kavin-114

@kavin-114 kavin-114 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

First release cut under the hotfix model: merges version-16-hotfix into version-16 and 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 version reads 16.2.0 instead of 0.0.1).

Backports in this PR (version-16-hotfix, newest last):

Already on version-16 since v16.1.0 (in the release notes, not in this diff): #1075, #1074, #1069, #1066, #998.

After merge the Release workflow (on this branch via #1099) tags the merge commit v16.2.0 and publishes the GitHub Release with generated notes from v16.1.0. Merge with a merge commit only.

Pre-merge checklist

  • CI is green
  • Branch is up to date with its base
  • New/changed behavior has tests (no new behavior; a release merge)
  • I self-reviewed the diff
  • If the base is version-N: this is the release PR from version-N-hotfix, __version__ is bumped, and release-source is green

https://claude.ai/code/session_01BhuU9nWobCxQe8JWiCzuo6

Navin-S-R and others added 9 commits September 2, 2026 08:25
…1071)

Backport of #1071. Hide the agent's internal built-in tools
(read/exec/…) from the chat "N tool calls" activity accordion, and keep the live
tool counter consistent with it (no 3→2 jump when a built-in finishes).
Frontend-only: a pure unit-tested predicate + a live-counter filter. See #1071.
…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)
kavin-114 and others added 20 commits September 3, 2026 19:09
…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)
venkat102 and others added 14 commits September 4, 2026 22:32
…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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants