@@ -4,6 +4,10 @@ language: "en-US" # USA English
44# It should not state additional information like: related issues, PRs, suggest reviewers
55# It should not continue a casual conversation with users that reply to it
66
7+ knowledge_base : # Enable knowledge base access for up-to-date information
8+ web_search : # Enable web search for up-to-date information
9+ enabled : true
10+
711# Only documents non-default options:
812reviews :
913 profile : " assertive" # Assertive profile yields more feedback, that may be considered nitpicky.
@@ -1055,6 +1059,114 @@ reviews:
10551059 - Correctly matches repository paths
10561060 - Enforces intended review governance
10571061 - Has no precedence bugs that weaken protection
1062+ # PROTOBUF INSTRUCTIONS
1063+ - path : " src/hiero_sdk_python/**/*.py"
1064+ instructions : |
1065+ ## Protobuf Schema Alignment Review
1066+
1067+ # ## Step 1 — Detect protobuf imports
1068+
1069+ Scan the file for all imports matching this pattern :
1070+ ` from hiero_sdk_python.hapi.<path> import <module>_pb2`
1071+
1072+ For each import found, skip `_grpc` stubs (those end in `_pb2_grpc`) — only
1073+ process `_pb2` message modules.
1074+
1075+ # ## Step 2 — Construct the canonical schema URL
1076+
1077+ For each `_pb2` import :
1078+ 1. Extract the path segment after `hapi`
1079+ (e.g. `services` from `hiero_sdk_python.hapi.services`)
1080+ 2. Extract the module name before `_pb2`
1081+ (e.g. `transaction_record` from `transaction_record_pb2`)
1082+ 3. Build the canonical URL :
1083+ ` https://github.com/hashgraph/hedera-protobufs/blob/v0.66.0/<path>/<module>.proto`
1084+
1085+ **Example:**
1086+ ` ` `
1087+ Import: from hiero_sdk_python.hapi.services import transaction_record_pb2
1088+ Schema: https://github.com/hashgraph/hedera-protobufs/blob/v0.66.0/services/transaction_record.proto
1089+ ` ` `
1090+
1091+ # ## Step 3 — Compare the SDK class against the proto schema
1092+
1093+ For each SDK class that calls `_from_proto` or `_to_proto` using messages from
1094+ the detected proto module, verify the following :
1095+
1096+ # ### 3a. Field coverage
1097+ - Every non-deprecated proto field SHOULD have a corresponding SDK attribute.
1098+ - Flag any proto field that is present in the schema but missing from the SDK
1099+ class (either as a dataclass field or handled in `_from_proto`).
1100+ - Flag any SDK attribute that references a proto field name that does not exist
1101+ in the schema.
1102+
1103+ # ### 3b. Field name mapping
1104+ - Proto field names use `snake_case` (e.g. `ethereum_hash`) or `camelCase`
1105+ (e.g. `transactionHash`, `consensusTimestamp`). Verify that `_from_proto`
1106+ accesses the correct proto field name, not a renamed/misspelled version.
1107+ - Verify `_to_proto` sets the correct proto field name.
1108+
1109+ # ### 3c. Field type alignment
1110+ Check that each SDK field type correctly represents the proto type :
1111+
1112+ | Proto type | Expected SDK type |
1113+ |------------------------|----------------------------------------------|
1114+ | `string` | `str \| None` or `str` |
1115+ | `bytes` | `bytes \| None` or `bytes` |
1116+ | `bool` | `bool` |
1117+ | `int32`, `uint32` | `int` |
1118+ | `int64`, `uint64`, `sint64` | `int` |
1119+ | `MessageType` | corresponding SDK wrapper class or `None` |
1120+ | `repeated MessageType` | `list[SdkType]` |
1121+ | `repeated scalar` | `list[scalar]` |
1122+
1123+ # ### 3d. `oneof` field handling
1124+ - Identify all `oneof` blocks in the proto schema for the message.
1125+ - Verify that `_to_proto` does NOT set more than one field from the same
1126+ ` oneof` block simultaneously. If it does, a `ValueError` guard MUST be
1127+ present before setting those fields.
1128+ - Verify that `_from_proto` uses `proto.HasField(...)` (not attribute access)
1129+ to detect which branch of a `oneof` is populated.
1130+ - Common `oneof` groups to watch for in `TransactionRecord` :
1131+ - ` oneof body { contractCallResult, contractCreateResult }` (fields 7, 8)
1132+ - ` oneof entropy { prng_bytes, prng_number }` (fields 19, 20)
1133+
1134+ # ### 3e. Bytes field normalization
1135+ - Proto `bytes` fields default to `b""` (empty bytes) when unset, not `None`.
1136+ - If the SDK models the field as `bytes | None`, verify that `_from_proto`
1137+ uses `proto.<field> or None` to normalize empty bytes to `None`.
1138+ - Conversely, if `_to_proto` sets a bytes field, verify it guards against
1139+ setting `None` (which would cause a protobuf type error).
1140+
1141+ # ### 3f. `_from_proto` / `_to_proto` symmetry
1142+ - Every field parsed in `_from_proto` SHOULD also be serialized in `_to_proto`,
1143+ and vice versa, unless the field is intentionally read-only (e.g. server-set
1144+ fields that clients never send).
1145+ - Flag any asymmetry that is not accompanied by a code comment explaining why.
1146+
1147+ # ### 3g. Repeated field default values
1148+ - SDK attributes representing proto `repeated` fields MUST default to an empty
1149+ list (`field(default_factory=list)`), never `None`.
1150+ - Flag any `repeated` field that defaults to `None`.
1151+
1152+ # ### 3h. Type annotation consistency
1153+ - The codebase uses `X | None` union syntax (Python 3.10+). Flag any use of
1154+ ` Optional[X]` from `typing` in newly added or modified code, as it is
1155+ inconsistent with the established style.
1156+
1157+ # ## Step 4 — Report format
1158+
1159+ For each issue found, report :
1160+ - **File and line**: where the issue occurs
1161+ - **Proto field**: the canonical proto field name and number from the schema
1162+ - **Issue type**: one of — Missing field | Wrong field name | Wrong type |
1163+ oneof violation | Bytes not normalized | Asymmetric round-trip |
1164+ Wrong default | Style inconsistency
1165+ - **Description**: concise explanation of the discrepancy
1166+ - **Suggested fix**: the corrected code snippet
1167+
1168+ If no issues are found for a file, state :
1169+ All mapped proto fields align with the schema at `<URL>`.
10581170 - path : " src/hiero_sdk_python/tokens/**/*.py"
10591171 instructions : *token_review_instructions
10601172 - path : " src/hiero_sdk_python/transaction/**/*.py"
@@ -1424,6 +1536,147 @@ reviews:
14241536 instructions : *node_review_instructions
14251537 - path : " src/hiero_sdk_python/file/**/*.py"
14261538 instructions : *file_review_instructions
1539+ - path : " src/hiero_sdk_python/consensus/**/*.py"
1540+ instructions : |
1541+ You are reviewing Python files in the `src/hiero_sdk_python/consensus/` directory.
1542+ These files implement consensus-related transactions and queries for the Hiero SDK.
1543+
1544+ > Note: Protobuf schema alignment (field names, types, oneof, bytes normalization,
1545+ > repeated defaults, and canonical `.proto` URL derivation) is already enforced by
1546+ > the global `src/hiero_sdk_python/**/*.py` instruction. Do NOT re-run those checks
1547+ > here — focus exclusively on the consensus-domain concerns below.
1548+
1549+ ---
1550+
1551+ ## Review priorities (highest → lowest)
1552+
1553+ ### 1) Protobuf correctness (must-not-break)
1554+ - Validate field names, field types, and (if visible/known) field numbers +
1555+ repeated/optional semantics.
1556+ - Flag any divergence as **BLOCKER**.
1557+
1558+ ### 2) Serialization / wire-format integrity
1559+ - Ensure `to_proto` / `from_proto` (or equivalent) set the correct oneof
1560+ branches and do not drop fields.
1561+ - Confirm byte/string encoding, timestamps/durations, and `TransactionID` /
1562+ `TopicID` mapping are correct.
1563+ - Treat silent coercions, defaulting, or ignored exceptions as **BLOCKER** if
1564+ they could change what is signed or sent.
1565+ - **Memo-overwrite trap**: any field whose Python default is `""` or `0` instead
1566+ of `None` and is later guarded by `if field is not None` will *always* serialize
1567+ — even when the caller never set it — silently overwriting the on-chain value.
1568+ Verify every optional update field defaults to `None`, not a falsy sentinel.
1569+ Flag as **BLOCKER** if the unintended overwrite affects keys, expiry, or memo.
1570+
1571+ ### 3) Signing / transaction body construction
1572+ - Verify the class builds the transaction/query body exactly once and uses the
1573+ correct protobuf message type.
1574+ - Ensure required fields are enforced before freezing/signing (if the SDK has a
1575+ freeze step).
1576+ - Missing required fields or signing the wrong body type is **BLOCKER**.
1577+
1578+ #### 3a) Multi-chunk TransactionID safety (`TopicMessageSubmitTransaction`)
1579+ When reviewing chunked message submission, verify all of the following:
1580+
1581+ **Nanos-overflow guard**
1582+ - In `freeze_with()`, the expression `base_timestamp.nanos + i` MUST be checked
1583+ for overflow. Protobuf `Timestamp.nanos` is bounded to `[0, 999_999_999]`.
1584+ If `nanos + num_chunks > 999_999_999` the value wraps or is rejected by the
1585+ node. An overflow guard MUST carry seconds over:
1586+ ```python
1587+ total_nanos = base_timestamp.nanos + i
1588+ chunk_valid_start = timestamp_pb2.Timestamp(
1589+ seconds=base_timestamp.seconds + total_nanos // 1_000_000_000,
1590+ nanos=total_nanos % 1_000_000_000
1591+ )
1592+ ```
1593+ Flag the absence of this guard as **BLOCKER**.
1594+
1595+ **`_initial_transaction_id` null-safety**
1596+ - `_build_proto_body()` calls `self._initial_transaction_id._to_proto()` when
1597+ `_total_chunks > 1`. If `freeze_with()` was never called (e.g. the caller
1598+ invokes `build_transaction_body()` directly on a multi-chunk message),
1599+ `_initial_transaction_id` is `None` and this raises `AttributeError` at
1600+ serialization time. An explicit `if self._initial_transaction_id is None`
1601+ guard with a descriptive `ValueError` MUST be present.
1602+ Flag as **BLOCKER**.
1603+
1604+ **Chunk signing consistency**
1605+ - In `execute()`, each chunk clears `_transaction_body_bytes` and
1606+ `_signature_map` then re-signs with every key in `_signing_keys`. Verify
1607+ that the re-sign loop uses the *stored* signing keys and not the operator
1608+ key only, so submit-key-protected topics are signed correctly for every chunk.
1609+ Flag any chunk that may be sent unsigned or with an incomplete signature set
1610+ as **BLOCKER**.
1611+
1612+ ### 4) Topic ID handling & validation
1613+ - Validate `TopicId` parsing, checksum/network validation (if applicable), and
1614+ conversion to protobuf.
1615+ - Check `from_string` for the bare `except Exception` catch: it loses the
1616+ original exception type; the re-raised `ValueError` should chain with `from e`
1617+ (already present) — verify the chaining is not accidentally removed.
1618+ - Incorrect network scoping/checksum behavior is **MAJOR** (or **BLOCKER** if
1619+ it can misroute funds/requests).
1620+ - **Frozen-dataclass checksum mutation**: `topic_id.py` uses
1621+ `object.__setattr__(topic_id, "checksum", checksum)` to bypass `frozen=True`.
1622+ Verify this is the only site where the frozen contract is broken, and that no
1623+ other attribute is mutated this way.
1624+
1625+ ### 5) Fees, limits, and defaults
1626+
1627+ #### 5a) Mutable default arguments in `__init__`
1628+ - Flag any mutable object used directly as a default parameter value in a method
1629+ signature. This is a Python anti-pattern because the object is shared across
1630+ all instances constructed without that argument.
1631+ - **Known instance**: `TopicUpdateTransaction.__init__` declares
1632+ `auto_renew_period: Optional[Duration] = Duration(7890000)`.
1633+ The fix is to default to `None` and assign in the body:
1634+ ```python
1635+ def __init__(self, ..., auto_renew_period: Optional[Duration] = None, ...):
1636+ ...
1637+ self.auto_renew_period = auto_renew_period if auto_renew_period is not None \
1638+ else Duration(7890000)
1639+ ```
1640+ Flag as **MAJOR** (shared mutable state across instances; mutating one
1641+ instance's default would silently affect others).
1642+ - Apply the same check to any `list` or `dict` default arguments.
1643+
1644+ #### 5b) Cross-class `transaction_fee` consistency
1645+ - Verify that the hardcoded `transaction_fee` defaults are intentional and
1646+ consistent across all sibling classes in this directory.
1647+ - Flag the **missing override** in `TopicMessageSubmitTransaction` as **MAJOR**
1648+ if the base-class default is not appropriate for message submission, or add a
1649+ comment confirming the base-class value is intentional.
1650+ - Flag any value that deviates from the table above without a comment as **MAJOR**.
1651+
1652+ #### 5c) General fee/limit logic
1653+ - Confirm any fee/max payment logic is consistent and does not allow unintended
1654+ "free" execution.
1655+ - Suspicious defaults or overflow/underflow issues are **MAJOR**.
1656+
1657+ ### 6) Errors & API ergonomics
1658+ - Errors should be actionable and consistent; avoid swallowing RPC/precheck errors.
1659+ - Ambiguous exceptions or inconsistent return types are **MINOR** / **MAJOR**
1660+ depending on impact.
1661+ - **`execute()` return-type consistency**: `TopicMessageSubmitTransaction.execute()`
1662+ returns `responses[0] if responses else None`. The `None` branch is unreachable
1663+ in practice (the loop always runs at least once for `num_chunks >= 2`) but
1664+ it makes the declared return type `TransactionReceipt | None`, which is
1665+ inconsistent with the single-chunk path. Flag as **MINOR**.
1666+
1667+ ### 7) Tests / examples (regression protection)
1668+ - Prefer tests that assert on produced protobufs (fields set, oneofs, ids).
1669+ - Cover: valid submit, missing topic id, empty message, large message boundary (if enforced), invalid checksum/network.
1670+ - Missing critical tests is **MAJOR** (or **MINOR** if coverage exists elsewhere).
1671+
1672+ ---
1673+
1674+ ## Severity labels
1675+ Use exactly these labels in all findings:
1676+ - **BLOCKER** — must be fixed before merge; wire-format, signing, or data-loss risk
1677+ - **MAJOR** — should be fixed; correctness or significant usability issue
1678+ - **MINOR** — should be fixed; low-risk correctness or ergonomics issue
1679+ - **NIT** — optional; style, naming, or documentation only
14271680
14281681chat :
14291682 art : false # Don't draw ASCII art (false)
0 commit comments