solomons-sword 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solomons_sword-0.1.3/.editorconfig +15 -0
- solomons_sword-0.1.3/.github/CODEOWNERS +1 -0
- solomons_sword-0.1.3/.github/dependabot.yml +32 -0
- solomons_sword-0.1.3/.github/workflows/ci.yml +49 -0
- solomons_sword-0.1.3/.github/workflows/codeql.yml +38 -0
- solomons_sword-0.1.3/.gitignore +22 -0
- solomons_sword-0.1.3/.mailmap +4 -0
- solomons_sword-0.1.3/DISCLAIMER.md +46 -0
- solomons_sword-0.1.3/LICENSE +21 -0
- solomons_sword-0.1.3/PKG-INFO +127 -0
- solomons_sword-0.1.3/README.md +99 -0
- solomons_sword-0.1.3/RELEASE_NOTES.md +40 -0
- solomons_sword-0.1.3/SECURITY.md +15 -0
- solomons_sword-0.1.3/louisgoldberg/__init__.py +46 -0
- solomons_sword-0.1.3/louisgoldberg/cli.py +123 -0
- solomons_sword-0.1.3/louisgoldberg/division6.py +233 -0
- solomons_sword-0.1.3/louisgoldberg/py.typed +0 -0
- solomons_sword-0.1.3/louisgoldberg/section100a.py +127 -0
- solomons_sword-0.1.3/louisgoldberg/section99b.py +99 -0
- solomons_sword-0.1.3/louisgoldberg/trust_resolution.py +59 -0
- solomons_sword-0.1.3/pyproject.toml +74 -0
- solomons_sword-0.1.3/tests/test_louisgoldberg.py +436 -0
- solomons_sword-0.1.3/tests/test_package_identity.py +56 -0
- solomons_sword-0.1.3/uv.lock +666 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.{yml,yaml,json,md,toml}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.md]
|
|
15
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @ryanduguid
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "github-actions"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
groups:
|
|
8
|
+
github-actions:
|
|
9
|
+
patterns:
|
|
10
|
+
- "*"
|
|
11
|
+
codeql-action:
|
|
12
|
+
patterns:
|
|
13
|
+
- "github/codeql-action*"
|
|
14
|
+
ignore:
|
|
15
|
+
# ADR-0001: the release-policy pin is an immutable full commit SHA,
|
|
16
|
+
# advanced only by a reviewed migration that also updates the pin
|
|
17
|
+
# assertion and verifies attestations against the new signer workflow.
|
|
18
|
+
# Dependabot can do neither, so its bumps are refused by the pin tests
|
|
19
|
+
# and sit red forever. Pin drift is tracked by release-policy's canary
|
|
20
|
+
# audit instead.
|
|
21
|
+
- dependency-name: "ryanduguid/release-policy/.github/workflows/*"
|
|
22
|
+
- package-ecosystem: "uv"
|
|
23
|
+
directory: "/"
|
|
24
|
+
schedule:
|
|
25
|
+
interval: "weekly"
|
|
26
|
+
cooldown:
|
|
27
|
+
default-days: 7
|
|
28
|
+
open-pull-requests-limit: 2
|
|
29
|
+
groups:
|
|
30
|
+
python:
|
|
31
|
+
patterns:
|
|
32
|
+
- "*"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: tests-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
name: pytest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
28
|
+
with:
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python }}
|
|
33
|
+
- name: install the locked toolchain
|
|
34
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
35
|
+
with:
|
|
36
|
+
version: "0.12.0"
|
|
37
|
+
enable-cache: true
|
|
38
|
+
- name: Ruff
|
|
39
|
+
run: uv run --locked --extra dev ruff check louisgoldberg tests
|
|
40
|
+
env:
|
|
41
|
+
UV_PYTHON: ${{ matrix.python }}
|
|
42
|
+
- name: Typecheck
|
|
43
|
+
run: uv run --locked --extra dev mypy louisgoldberg
|
|
44
|
+
env:
|
|
45
|
+
UV_PYTHON: ${{ matrix.python }}
|
|
46
|
+
- name: Run tests
|
|
47
|
+
run: uv run --locked --extra dev pytest -q
|
|
48
|
+
env:
|
|
49
|
+
UV_PYTHON: ${{ matrix.python }}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "23 3 * * 1"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
analyze:
|
|
17
|
+
name: Analyze Python
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 30
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
security-events: write # Upload CodeQL results for this job only.
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out source
|
|
25
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
|
|
29
|
+
- name: Initialise CodeQL
|
|
30
|
+
uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
|
|
31
|
+
with:
|
|
32
|
+
languages: python
|
|
33
|
+
build-mode: none
|
|
34
|
+
|
|
35
|
+
- name: Perform CodeQL analysis
|
|
36
|
+
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
|
|
37
|
+
with:
|
|
38
|
+
category: "/language:python"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
|
|
11
|
+
# Unit test / coverage
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.coverage
|
|
14
|
+
htmlcov/
|
|
15
|
+
|
|
16
|
+
# Environments
|
|
17
|
+
.env
|
|
18
|
+
.venv
|
|
19
|
+
env/
|
|
20
|
+
venv/
|
|
21
|
+
.env.*
|
|
22
|
+
!.env.example
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Disclaimer
|
|
2
|
+
|
|
3
|
+
Solomon's Sword allocates trust income on proportionate entitlement under
|
|
4
|
+
Division 6 of the ITAA 1936 and evaluates caller-supplied facts against
|
|
5
|
+
Section 100A, Section 99B and 30 June resolution requirements. It is not tax,
|
|
6
|
+
legal, accounting, financial, investment, BAS-agent, registered-tax-agent, or
|
|
7
|
+
assurance advice. It is not an assessment, a private ruling, or a
|
|
8
|
+
determination.
|
|
9
|
+
|
|
10
|
+
This project is not affiliated with, sponsored by, endorsed by, or approved by:
|
|
11
|
+
|
|
12
|
+
- the Australian Taxation Office
|
|
13
|
+
- the Commonwealth of Australia
|
|
14
|
+
- any state or territory revenue office
|
|
15
|
+
- Chartered Accountants Australia and New Zealand
|
|
16
|
+
- any law firm, court, or tribunal
|
|
17
|
+
|
|
18
|
+
Outputs can be wrong, incomplete, stale, or unsuitable for a given set of
|
|
19
|
+
facts. Tax law, ATO guidance, practical compliance guidelines, rates and
|
|
20
|
+
thresholds change, and the engine sees only the facts it is handed. Confirm
|
|
21
|
+
every allocation, zone and exemption against the current law, the trust deed
|
|
22
|
+
and the entity's facts before acting, and leave lodgment decisions with a
|
|
23
|
+
registered practitioner.
|
|
24
|
+
|
|
25
|
+
Coverage is deliberately partial. Specifically streamed capital gains and
|
|
26
|
+
franked dividends, non-resident beneficiaries under s 98(2A) and s 98(3), nil
|
|
27
|
+
income of the trust estate, and s 99 or s 99A cases are refused rather than
|
|
28
|
+
allocated, because the Division 6E carve-out with Subdivision 115-C and
|
|
29
|
+
Subdivision 207-B is not implemented. A refusal is the engine declining to
|
|
30
|
+
answer, not a finding that no amount is assessable. The Section 100A matrix
|
|
31
|
+
returns only the zones the engine implements and does not decide the white
|
|
32
|
+
zone.
|
|
33
|
+
|
|
34
|
+
Nothing here lodges a trust tax return, a distribution statement, or any other
|
|
35
|
+
official form, posts journals, or sends client correspondence. Workpapers and
|
|
36
|
+
calculations are draft preparation artefacts.
|
|
37
|
+
|
|
38
|
+
Command output carries the beneficiary name supplied to it. Treat that output
|
|
39
|
+
as client data, write it to the firm's approved secure location, and never to
|
|
40
|
+
a path inside a repository. Do not publish private tax records, trust deeds,
|
|
41
|
+
TFNs, Medicare numbers, bank details, identity documents, or other sensitive
|
|
42
|
+
personal information in issues, pull requests, examples, tests, or repository
|
|
43
|
+
content. Fixtures in this repository are fabricated.
|
|
44
|
+
|
|
45
|
+
See [LICENSE](LICENSE) for copyright and [SECURITY.md](SECURITY.md) for
|
|
46
|
+
vulnerability reporting.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Duguid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: solomons-sword
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Trust distribution allocation, Section 100A / 99B risk evaluation, and Division 6 ITAA 1936 compliance for Australian trusts.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ryanduguid/australian-accounting/tree/main/packages/solomons-sword
|
|
6
|
+
Project-URL: Repository, https://github.com/ryanduguid/australian-accounting/tree/main/packages/solomons-sword
|
|
7
|
+
Project-URL: Issues, https://github.com/ryanduguid/australian-accounting/issues
|
|
8
|
+
Author-email: Ryan Duguid <ryan@duguid.com.au>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: accounting,australian-tax,bamford,division-6,itaa1936,section-100a,section-99b,trust-accounting
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
23
|
+
Requires-Dist: mypy>=1.14; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# Solomon's Sword
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
+----------------------------------------------------------------------+
|
|
33
|
+
| SolomonsSword |
|
|
34
|
+
+----------------------------------------------------------------------+
|
|
35
|
+
| Division 6, s100A and s99B trust review tools |
|
|
36
|
+
+----------------------------------+-----------------------------------+
|
|
37
|
+
| DR what it gives you | CR what it needs |
|
|
38
|
+
+----------------------------------+-----------------------------------+
|
|
39
|
+
| s100A green red risk zones | beneficiary and amount data |
|
|
40
|
+
| s99B foreign trust review | trust facts like corpus value |
|
|
41
|
+
| Division 6 allocation review | - |
|
|
42
|
+
+----------------------------------+-----------------------------------+
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
[](https://www.python.org/)
|
|
46
|
+
[](https://github.com/ryanduguid/australian-accounting/actions/workflows/ci-solomons-sword.yml)
|
|
47
|
+
[](https://pypi.org/project/solomons-sword/)
|
|
48
|
+
[](https://opensource.org/licenses/MIT)
|
|
49
|
+
[](https://www.legislation.gov.au/C1936A00027/latest/text)
|
|
50
|
+
|
|
51
|
+
**Trust distribution allocation, Section 100A / 99B risk evaluation, and Division 6 ITAA 1936 review helpers for Australian trusts.**
|
|
52
|
+
|
|
53
|
+
**Package lifecycle:** published. Install `solomons-sword` from PyPI.
|
|
54
|
+
|
|
55
|
+
The `australian-accounting` repository contains the maintained source. The
|
|
56
|
+
`solomons-sword` distribution and command match the project identity. The
|
|
57
|
+
`louisgoldberg` import package remains unchanged, so internal Python imports do
|
|
58
|
+
not need a rename.
|
|
59
|
+
|
|
60
|
+
Release: [`v0.1.3`](https://github.com/ryanduguid/australian-accounting/releases/tag/solomons-sword/v0.1.3).
|
|
61
|
+
|
|
62
|
+
Named for the judgement of Solomon, where the threat of dividing the child in proportion is what reveals who the true claimant is. Division 6 allocates trust income by proportionate entitlement following *Bamford*; Section 100A asks who actually ended up with the benefit. The name is a tribute only.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Not advice
|
|
66
|
+
|
|
67
|
+
Nothing this engine produces is tax, legal or financial advice, an assessment or
|
|
68
|
+
a determination. Outputs are review aids: confirm every allocation, zone and
|
|
69
|
+
exemption against the current law, the trust deed and the entity's facts before
|
|
70
|
+
acting, and leave lodgment decisions with a registered practitioner. Where the
|
|
71
|
+
model does not implement a rule it refuses the input rather than returning a
|
|
72
|
+
number it cannot stand behind.
|
|
73
|
+
|
|
74
|
+
Command output carries the beneficiary name you supply, because a workpaper line
|
|
75
|
+
item is unusable without it. Treat that output as client data: write it to the
|
|
76
|
+
firm's approved secure location, never to a path inside a repository.
|
|
77
|
+
|
|
78
|
+
Full boundary statement: [DISCLAIMER.md](https://github.com/ryanduguid/australian-accounting/blob/main/packages/solomons-sword/DISCLAIMER.md).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Core Features
|
|
83
|
+
|
|
84
|
+
- **Division 6 Proportionate Allocation (*Commissioner of Taxation v Bamford* [2010] HCA 10)**: Calculates present entitlement proportions and allocates *s 95(1) ITAA 1936* taxable net income and the franking credits that ride with it. Specifically streamed capital gains and franked dividends are **refused**, not allocated: the Division 6E carve-out with *Subdivision 115-C* (including s 115-220) and *Subdivision 207-B* is not implemented, so a proportionate answer would be wrong. Non-resident beneficiaries (*s 98(2A)/(3)*), nil income of the trust estate and no presently entitled beneficiary (*s 99 / s 99A*) are refused for the same reason.
|
|
85
|
+
- **Section 100A Reimbursement Agreement Matrix**: Classifies supplied facts against **ATO PCG 2022/2** as Green, Red, or outside those zones. The final guideline has white, green and red; the draft blue zone did not survive. White zone (income years ending before 1 July 2014) is out of scope because the function does not take an income year.
|
|
86
|
+
- **Section 99B Foreign Trust Receipt Assessment**: Computes assessable amounts under *s 99B(1)* after corpus exemptions (*s 99B(2)(a)*) and prior-taxed income.
|
|
87
|
+
- **Trust Resolution 30 June Schedule Verifier**: Checks timing, deed-power and percentage-completeness facts the caller supplies.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Quickstart
|
|
92
|
+
|
|
93
|
+
### Installation
|
|
94
|
+
```bash
|
|
95
|
+
pip install solomons-sword
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### CLI Usage
|
|
99
|
+
```bash
|
|
100
|
+
# Evaluate Section 100A risk zone
|
|
101
|
+
solomons-sword s100a-check --beneficiary "Adult Child" --amount 40000 --adult-child --retained-by-parents
|
|
102
|
+
|
|
103
|
+
# Assess Section 99B receipt from foreign trust with corpus deduction
|
|
104
|
+
solomons-sword s99b-check --beneficiary "Jane Doe" --gross 150000 --corpus 50000
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Statutory Ground Truth & Test Harness
|
|
110
|
+
|
|
111
|
+
All allocation and threshold algorithms use exact `decimal.Decimal` calculations to prevent rounding discrepancies in trust tax schedules.
|
|
112
|
+
|
|
113
|
+
| Statutory Domain | Primary Authority | What the code actually does |
|
|
114
|
+
| :--- | :--- | :--- |
|
|
115
|
+
| **Proportionate Entitlement** | *ITAA 1936* s 95, s 97 (*Commissioner of Taxation v Bamford* [2010] HCA 10) | `Beneficiary Share = (Accounting Entitlement / Total Accounting Income) * s95 Net Income`. |
|
|
116
|
+
| **Section 100A Risk Matrix** | *ITAA 1936* s 100A, *ATO PCG 2022/2* | Returns GREEN, RED or OUTSIDE_GREEN from the supplied flags. It does not decide the white zone. |
|
|
117
|
+
| **Foreign Trust Distributions** | *ITAA 1936* s 99B(1), s 99B(2)(a) | Subtracts settled corpus and previously taxed income prior to assessable inclusion. |
|
|
118
|
+
| **Trust Resolution Timing** | Caller-supplied deed and execution facts | Refuses incomplete percentages and missing deed facts. This is not a substitute for current ATO guidance. |
|
|
119
|
+
|
|
120
|
+
### Automated Test Suite
|
|
121
|
+
- Run the suite: `pytest tests/`
|
|
122
|
+
- The suite covers proportionate streaming, Section 100A zones the engine implements, Section 99B corpus deductions, and resolution gates. Do not treat a badge as a live coverage certificate.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Licence
|
|
127
|
+
MIT License. Created by Ryan Duguid.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Solomon's Sword
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
+----------------------------------------------------------------------+
|
|
5
|
+
| SolomonsSword |
|
|
6
|
+
+----------------------------------------------------------------------+
|
|
7
|
+
| Division 6, s100A and s99B trust review tools |
|
|
8
|
+
+----------------------------------+-----------------------------------+
|
|
9
|
+
| DR what it gives you | CR what it needs |
|
|
10
|
+
+----------------------------------+-----------------------------------+
|
|
11
|
+
| s100A green red risk zones | beneficiary and amount data |
|
|
12
|
+
| s99B foreign trust review | trust facts like corpus value |
|
|
13
|
+
| Division 6 allocation review | - |
|
|
14
|
+
+----------------------------------+-----------------------------------+
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
[](https://www.python.org/)
|
|
18
|
+
[](https://github.com/ryanduguid/australian-accounting/actions/workflows/ci-solomons-sword.yml)
|
|
19
|
+
[](https://pypi.org/project/solomons-sword/)
|
|
20
|
+
[](https://opensource.org/licenses/MIT)
|
|
21
|
+
[](https://www.legislation.gov.au/C1936A00027/latest/text)
|
|
22
|
+
|
|
23
|
+
**Trust distribution allocation, Section 100A / 99B risk evaluation, and Division 6 ITAA 1936 review helpers for Australian trusts.**
|
|
24
|
+
|
|
25
|
+
**Package lifecycle:** published. Install `solomons-sword` from PyPI.
|
|
26
|
+
|
|
27
|
+
The `australian-accounting` repository contains the maintained source. The
|
|
28
|
+
`solomons-sword` distribution and command match the project identity. The
|
|
29
|
+
`louisgoldberg` import package remains unchanged, so internal Python imports do
|
|
30
|
+
not need a rename.
|
|
31
|
+
|
|
32
|
+
Release: [`v0.1.3`](https://github.com/ryanduguid/australian-accounting/releases/tag/solomons-sword/v0.1.3).
|
|
33
|
+
|
|
34
|
+
Named for the judgement of Solomon, where the threat of dividing the child in proportion is what reveals who the true claimant is. Division 6 allocates trust income by proportionate entitlement following *Bamford*; Section 100A asks who actually ended up with the benefit. The name is a tribute only.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Not advice
|
|
38
|
+
|
|
39
|
+
Nothing this engine produces is tax, legal or financial advice, an assessment or
|
|
40
|
+
a determination. Outputs are review aids: confirm every allocation, zone and
|
|
41
|
+
exemption against the current law, the trust deed and the entity's facts before
|
|
42
|
+
acting, and leave lodgment decisions with a registered practitioner. Where the
|
|
43
|
+
model does not implement a rule it refuses the input rather than returning a
|
|
44
|
+
number it cannot stand behind.
|
|
45
|
+
|
|
46
|
+
Command output carries the beneficiary name you supply, because a workpaper line
|
|
47
|
+
item is unusable without it. Treat that output as client data: write it to the
|
|
48
|
+
firm's approved secure location, never to a path inside a repository.
|
|
49
|
+
|
|
50
|
+
Full boundary statement: [DISCLAIMER.md](https://github.com/ryanduguid/australian-accounting/blob/main/packages/solomons-sword/DISCLAIMER.md).
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Core Features
|
|
55
|
+
|
|
56
|
+
- **Division 6 Proportionate Allocation (*Commissioner of Taxation v Bamford* [2010] HCA 10)**: Calculates present entitlement proportions and allocates *s 95(1) ITAA 1936* taxable net income and the franking credits that ride with it. Specifically streamed capital gains and franked dividends are **refused**, not allocated: the Division 6E carve-out with *Subdivision 115-C* (including s 115-220) and *Subdivision 207-B* is not implemented, so a proportionate answer would be wrong. Non-resident beneficiaries (*s 98(2A)/(3)*), nil income of the trust estate and no presently entitled beneficiary (*s 99 / s 99A*) are refused for the same reason.
|
|
57
|
+
- **Section 100A Reimbursement Agreement Matrix**: Classifies supplied facts against **ATO PCG 2022/2** as Green, Red, or outside those zones. The final guideline has white, green and red; the draft blue zone did not survive. White zone (income years ending before 1 July 2014) is out of scope because the function does not take an income year.
|
|
58
|
+
- **Section 99B Foreign Trust Receipt Assessment**: Computes assessable amounts under *s 99B(1)* after corpus exemptions (*s 99B(2)(a)*) and prior-taxed income.
|
|
59
|
+
- **Trust Resolution 30 June Schedule Verifier**: Checks timing, deed-power and percentage-completeness facts the caller supplies.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quickstart
|
|
64
|
+
|
|
65
|
+
### Installation
|
|
66
|
+
```bash
|
|
67
|
+
pip install solomons-sword
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### CLI Usage
|
|
71
|
+
```bash
|
|
72
|
+
# Evaluate Section 100A risk zone
|
|
73
|
+
solomons-sword s100a-check --beneficiary "Adult Child" --amount 40000 --adult-child --retained-by-parents
|
|
74
|
+
|
|
75
|
+
# Assess Section 99B receipt from foreign trust with corpus deduction
|
|
76
|
+
solomons-sword s99b-check --beneficiary "Jane Doe" --gross 150000 --corpus 50000
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Statutory Ground Truth & Test Harness
|
|
82
|
+
|
|
83
|
+
All allocation and threshold algorithms use exact `decimal.Decimal` calculations to prevent rounding discrepancies in trust tax schedules.
|
|
84
|
+
|
|
85
|
+
| Statutory Domain | Primary Authority | What the code actually does |
|
|
86
|
+
| :--- | :--- | :--- |
|
|
87
|
+
| **Proportionate Entitlement** | *ITAA 1936* s 95, s 97 (*Commissioner of Taxation v Bamford* [2010] HCA 10) | `Beneficiary Share = (Accounting Entitlement / Total Accounting Income) * s95 Net Income`. |
|
|
88
|
+
| **Section 100A Risk Matrix** | *ITAA 1936* s 100A, *ATO PCG 2022/2* | Returns GREEN, RED or OUTSIDE_GREEN from the supplied flags. It does not decide the white zone. |
|
|
89
|
+
| **Foreign Trust Distributions** | *ITAA 1936* s 99B(1), s 99B(2)(a) | Subtracts settled corpus and previously taxed income prior to assessable inclusion. |
|
|
90
|
+
| **Trust Resolution Timing** | Caller-supplied deed and execution facts | Refuses incomplete percentages and missing deed facts. This is not a substitute for current ATO guidance. |
|
|
91
|
+
|
|
92
|
+
### Automated Test Suite
|
|
93
|
+
- Run the suite: `pytest tests/`
|
|
94
|
+
- The suite covers proportionate streaming, Section 100A zones the engine implements, Section 99B corpus deductions, and resolution gates. Do not treat a badge as a live coverage certificate.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Licence
|
|
99
|
+
MIT License. Created by Ryan Duguid.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# v0.1.3
|
|
2
|
+
|
|
3
|
+
This is the first PyPI release of `solomons-sword`.
|
|
4
|
+
The monorepo's [filtered GitHub Releases page](https://github.com/ryanduguid/australian-accounting/releases?q=solomons-sword)
|
|
5
|
+
is the canonical release history.
|
|
6
|
+
|
|
7
|
+
- Move the maintained source to `packages/solomons-sword` in the
|
|
8
|
+
`australian-accounting` monorepo.
|
|
9
|
+
- Publish through `release-solomons-sword.yml`, using the monorepo's
|
|
10
|
+
namespaced, attested release workflow.
|
|
11
|
+
- Preserve the v0.1.2 Division 6, Section 100A and Section 99B behavior.
|
|
12
|
+
|
|
13
|
+
# v0.1.2
|
|
14
|
+
|
|
15
|
+
Releases through v0.1.2 are recorded on the standalone repository's
|
|
16
|
+
[GitHub Releases page](https://github.com/ryanduguid/SolomonsSword/releases).
|
|
17
|
+
A separate changelog is intentionally not maintained.
|
|
18
|
+
|
|
19
|
+
Prepared 0.1.2 notes. No PyPI distribution has been published; this source-only
|
|
20
|
+
project currently installs from a clone. The statutory corrections below came
|
|
21
|
+
from an audit whose claims were checked against the ITAA 1936 compilation in
|
|
22
|
+
force from 1 July 2026 and the High Court's own citation of Bamford:
|
|
23
|
+
|
|
24
|
+
- Division 6 franking credits were allocated on two overlapping bases when dividends were streamed, distributing 150 per cent of the credit pool in the audited case. Streaming is now refused outright, because the Division 6E carve-out with Subdivisions 115-C and 207-B is not implemented and a proportionate answer would be wrong.
|
|
25
|
+
- The franking credit gross-up is no longer added on top of the s 95 net income share: s 207-35 ITAA 1997 already includes it in the trust's net income, so adding it counted the credits twice. It is reported separately for the s 207-45 offset.
|
|
26
|
+
- Allocation now carries unrounded ratios into the s 95 pool and assigns the rounding residual, so allocated shares reconcile to the net income exactly. Three equal thirds of $100,000 previously lost $10.
|
|
27
|
+
- Cases the model does not compute now fail closed instead of returning an empty list or a mislabelled section: no presently entitled beneficiary and nil income of the trust estate (s 99 or s 99A trustee assessment), and non-resident beneficiaries (s 98(2A) or s 98(3)).
|
|
28
|
+
- Entitlements outside 0 to 100 per cent are refused; a 150 per cent and negative 50 per cent pair previously allocated a negative assessable share.
|
|
29
|
+
- s 99B now models the s 99B(1) residency precondition, the s 99B(2)(a) proviso for corpus attributable to amounts that would have been assessable to a resident, and the s 99B(2)(b) limb; negative inputs and exemptions exceeding the receipt are refused.
|
|
30
|
+
- The PCG 2022/2 green zone no longer claims the s 100A(13) ordinary family dealing exception. The guideline is a compliance-resourcing stance, not a determination, and the ordinary-family-dealing field is undetermined for that zone.
|
|
31
|
+
- Bamford is cited correctly as Commissioner of Taxation v Bamford [2010] HCA 10; (2010) 240 CLR 481, and the streaming reference reads Subdivisions 115-C and 207-B.
|
|
32
|
+
|
|
33
|
+
Also: one version source, project URLs, mypy enforced in CI (five real errors
|
|
34
|
+
fixed) with Python 3.11 and 3.13 added, CodeQL, deduplicated Dependabot config,
|
|
35
|
+
a not-advice boundary in the README, module docstrings and CLI output. The
|
|
36
|
+
package release workflow is intentionally absent until publication has a named
|
|
37
|
+
user, a fresh index-name availability check and an explicit compatibility
|
|
38
|
+
contract.
|
|
39
|
+
|
|
40
|
+
Not advice. Outputs are review aids for a qualified professional, not determinations.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are applied to the latest version on the default branch.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Use this repository's private vulnerability-reporting feature (Security > Report a vulnerability). Do not open a public issue or pull request for a suspected vulnerability.
|
|
10
|
+
|
|
11
|
+
Include a clear description, reproduction steps using fabricated data, likely impact, and any suggested mitigation. Never include client, taxpayer, employee, payroll, access-token or other sensitive data.
|
|
12
|
+
|
|
13
|
+
A valid report will be acknowledged within seven days. The fix and disclosure timeline will be agreed with the reporter.
|
|
14
|
+
|
|
15
|
+
If GitHub private reporting is not visible, email is not published as a fallback on purpose: enable private reporting in repository settings rather than creating a public inbox.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Solomon's Sword: Trust Distribution & Section 100A / 99B Risk Engine
|
|
3
|
+
The distribution is `solomons-sword`; the import package remains `louisgoldberg`.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, version as _dist_version
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
__version__ = _dist_version("solomons-sword")
|
|
10
|
+
except PackageNotFoundError: # running from a source tree without installation
|
|
11
|
+
__version__ = "0.0.0.dev0"
|
|
12
|
+
__author__ = "Ryan Duguid"
|
|
13
|
+
|
|
14
|
+
from .division6 import (
|
|
15
|
+
TrustIncomeAssessment,
|
|
16
|
+
BeneficiaryEntitlement,
|
|
17
|
+
calculate_proportionate_share,
|
|
18
|
+
)
|
|
19
|
+
from .section100a import (
|
|
20
|
+
Section100ARiskZone,
|
|
21
|
+
Section100AAssessment,
|
|
22
|
+
evaluate_section100a_risk,
|
|
23
|
+
)
|
|
24
|
+
from .section99b import (
|
|
25
|
+
ForeignTrustReceipt,
|
|
26
|
+
Section99BAssessment,
|
|
27
|
+
evaluate_section99b_liability,
|
|
28
|
+
)
|
|
29
|
+
from .trust_resolution import (
|
|
30
|
+
TrustResolutionSchedule,
|
|
31
|
+
validate_trust_resolution,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"TrustIncomeAssessment",
|
|
36
|
+
"BeneficiaryEntitlement",
|
|
37
|
+
"calculate_proportionate_share",
|
|
38
|
+
"Section100ARiskZone",
|
|
39
|
+
"Section100AAssessment",
|
|
40
|
+
"evaluate_section100a_risk",
|
|
41
|
+
"ForeignTrustReceipt",
|
|
42
|
+
"Section99BAssessment",
|
|
43
|
+
"evaluate_section99b_liability",
|
|
44
|
+
"TrustResolutionSchedule",
|
|
45
|
+
"validate_trust_resolution",
|
|
46
|
+
]
|