Split administrative-correction into typed development/remission corrections
Resolves the WP-0003-T06 review flag: the single administrative-correction
ledger entry type had an unstated fold-side effect (concept §17 names the
type but never says which side of the target it corrects). Maintainer chose
option (a) — split into administrative-correction-development and
administrative-correction-remission so the corrected side is explicit in
the type name rather than an implicit library default.
- schemas/ledger_entry.schema.json: enum split, no other behavior change.
- src/target_revenue/fold.py: each new type maps to its named side only.
- specs/TargetLedgerSpecification.md, TechnicalSpecificationDocument.md
§3.2, ProductRequirementsDocument.md FR-5: updated to the split types.
- tests/test_ledger_fold.py: dedicated coverage for both new types plus a
regression test that the old unsplit type name is now rejected.
spec/TargetRevenueLicenseConcept.md §17 is left unedited — its entry-type
list is explicitly non-exhaustive ("may include"), so this specializes
rather than contradicts it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
754d104b7a
commit
2b675c11ad
7 changed files with 129 additions and 29 deletions
|
|
@ -131,3 +131,81 @@ def test_remission_correction_can_reduce_over_remission():
|
|||
result = fold.fold_outstanding_target(100000, entries)
|
||||
assert result.remission_credit == 15000
|
||||
assert result.outstanding_target == 85000
|
||||
|
||||
|
||||
def test_administrative_correction_development_adjusts_development_side():
|
||||
entries = [
|
||||
{
|
||||
"id": "trsl:entry:t0001",
|
||||
"phase": "trsl:phase:t",
|
||||
"type": "administrative-correction-development",
|
||||
"amount": 3000,
|
||||
"currency": "USD",
|
||||
"recognized_at": "2026-01-01T00:00:00Z",
|
||||
"evidence_reference": "confidential:evidence:t0001-admin",
|
||||
"previous_entry_hash": "GENESIS",
|
||||
},
|
||||
]
|
||||
result = fold.fold_outstanding_target(100000, entries)
|
||||
assert result.development_credit == 3000
|
||||
assert result.remission_credit == 0
|
||||
assert result.outstanding_target == 97000
|
||||
|
||||
|
||||
def test_administrative_correction_remission_adjusts_remission_side():
|
||||
entries = [
|
||||
{
|
||||
"id": "trsl:entry:t0001",
|
||||
"phase": "trsl:phase:t",
|
||||
"type": "administrative-correction-remission",
|
||||
"amount": 3000,
|
||||
"currency": "USD",
|
||||
"recognized_at": "2026-01-01T00:00:00Z",
|
||||
"evidence_reference": "confidential:evidence:t0001-admin",
|
||||
"previous_entry_hash": "GENESIS",
|
||||
},
|
||||
]
|
||||
result = fold.fold_outstanding_target(100000, entries)
|
||||
assert result.development_credit == 0
|
||||
assert result.remission_credit == 3000
|
||||
assert result.outstanding_target == 97000
|
||||
|
||||
|
||||
def test_administrative_correction_types_are_schema_valid():
|
||||
from target_revenue import validation
|
||||
|
||||
for entry_type in (
|
||||
"administrative-correction-development",
|
||||
"administrative-correction-remission",
|
||||
):
|
||||
entry = {
|
||||
"id": "trsl:entry:t0001",
|
||||
"phase": "trsl:phase:t",
|
||||
"type": entry_type,
|
||||
"amount": 100,
|
||||
"currency": "USD",
|
||||
"recognized_at": "2026-01-01T00:00:00Z",
|
||||
"evidence_reference": "confidential:evidence:t0001",
|
||||
"previous_entry_hash": "GENESIS",
|
||||
}
|
||||
validation.validate_ledger_entry(entry)
|
||||
|
||||
|
||||
def test_old_unsplit_administrative_correction_type_is_no_longer_valid():
|
||||
"""The single ambiguous administrative-correction type was split
|
||||
2026-07-29 (specs/TargetLedgerSpecification.md §2); it must no longer
|
||||
validate as a known type."""
|
||||
from target_revenue import validation
|
||||
|
||||
entry = {
|
||||
"id": "trsl:entry:t0001",
|
||||
"phase": "trsl:phase:t",
|
||||
"type": "administrative-correction",
|
||||
"amount": 100,
|
||||
"currency": "USD",
|
||||
"recognized_at": "2026-01-01T00:00:00Z",
|
||||
"evidence_reference": "confidential:evidence:t0001",
|
||||
"previous_entry_hash": "GENESIS",
|
||||
}
|
||||
with pytest.raises(validation.ConformanceError):
|
||||
validation.validate_ledger_entry(entry)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue