{
  "tool_id": "art-705-bond-ladder-builder",
  "note": "Synthetic golden vectors F1-F8 (no external data). F1 single-rung ladder equals the art-329/330/331 primitive outputs exactly (parity gate). F3 weights not summing to 1 refused (refusal names the sum). F4 zero-coupon rung. F7 doubles F2 notional: DV01 scales 2x, duration unchanged (proptest cross-check). golden_hash pinned via node golden-parity.test.mjs --update. human_sign_off: PENDING.",
  "vectors": [
    {
      "name": "F1_single_rung_ladder",
      "policy_parameters": {
        "notional": 100000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 5,
            "coupon_rate_pct": 4.5,
            "yield_pct": 4.2,
            "target_weight": 1
          }
        ]
      },
      "output_payload": {
        "notional": 100000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "num_rungs": 1,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 5,
            "weight": 1,
            "notional": 100000,
            "price": 101340.37,
            "duration": 4.536614,
            "modified_duration": 4.443305,
            "dv01": 45.028616,
            "convexity": 23.142858
          }
        ],
        "portfolio": {
          "weighted_duration": 4.536614,
          "weighted_modified_duration": 4.443305,
          "weighted_dv01": 45.028616,
          "weighted_convexity": 23.142858
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 2 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (hold_to_maturity): every coupon payment and every maturing rung's principal are held as cash earning 0% after receipt — nothing is reinvested and nothing is rolled into other rungs. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung's contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "4876027a1b25ca5bc835e7b17f0c19d1b90b04254b36528779b6f5dadb33aa79"
    },
    {
      "name": "F2_three_rung_ladder",
      "policy_parameters": {
        "notional": 300000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 1,
            "coupon_rate_pct": 4,
            "yield_pct": 4.1,
            "target_weight": 0.3333333333333333
          },
          {
            "maturity_years": 3,
            "coupon_rate_pct": 4.25,
            "yield_pct": 4.3,
            "target_weight": 0.3333333333333333
          },
          {
            "maturity_years": 5,
            "coupon_rate_pct": 4.5,
            "yield_pct": 4.5,
            "target_weight": 0.3333333333333333
          }
        ]
      },
      "output_payload": {
        "notional": 300000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "num_rungs": 3,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 1,
            "weight": 0.3333333333333333,
            "notional": 100000,
            "price": 99902.99,
            "duration": 0.990191,
            "modified_duration": 0.9703,
            "dv01": 9.69359,
            "convexity": 1.421504
          },
          {
            "rung": 2,
            "maturity_years": 3,
            "weight": 0.3333333333333333,
            "notional": 100000,
            "price": 99860.67,
            "duration": 2.848078,
            "modified_duration": 2.788133,
            "dv01": 27.842482,
            "convexity": 9.385603
          },
          {
            "rung": 3,
            "maturity_years": 5,
            "weight": 0.3333333333333333,
            "notional": 100000,
            "price": 100000,
            "duration": 4.532853,
            "modified_duration": 4.433108,
            "dv01": 44.331084,
            "convexity": 23.050364
          }
        ],
        "portfolio": {
          "weighted_duration": 2.790374,
          "weighted_modified_duration": 2.730514,
          "weighted_dv01": 27.289052,
          "weighted_convexity": 11.285824
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 2 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (hold_to_maturity): every coupon payment and every maturing rung's principal are held as cash earning 0% after receipt — nothing is reinvested and nothing is rolled into other rungs. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung's contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "9bf825fd9e760e624c2dd908f8a5a8d48abb7b6d27147d0efc2ab93f3b1b322b"
    },
    {
      "name": "F3_weights_not_summing_to_one_refused",
      "policy_parameters": {
        "notional": 100000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 2,
            "coupon_rate_pct": 4,
            "yield_pct": 4,
            "target_weight": 0.5
          },
          {
            "maturity_years": 4,
            "coupon_rate_pct": 4,
            "yield_pct": 4,
            "target_weight": 0.5000001
          }
        ]
      },
      "output_payload": {
        "error": "weights_sum_not_one",
        "detail": "rung target_weight values must sum to 1 within 1e-9; they sum to 1.0000000999999998 (difference 9.999999983634211e-8 from 1).",
        "domain_errors": [
          {
            "code": "WEIGHTS_SUM_NOT_ONE",
            "text": "rung target_weight values must sum to 1 within 1e-9; they sum to 1.0000000999999998 (difference 9.999999983634211e-8 from 1)."
          }
        ],
        "ladder": null,
        "portfolio": null,
        "assumptions": []
      },
      "golden_hash": "5ef7d25185c0231d9f5713d68fbbac9c6150a7144b2f6d816c82ff60e41aab35"
    },
    {
      "name": "F4_zero_coupon_rung",
      "policy_parameters": {
        "notional": 50000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 2,
            "coupon_rate_pct": 0,
            "yield_pct": 4.4,
            "target_weight": 0.4
          },
          {
            "maturity_years": 6,
            "coupon_rate_pct": 4.75,
            "yield_pct": 4.6,
            "target_weight": 0.6
          }
        ]
      },
      "output_payload": {
        "notional": 50000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "num_rungs": 2,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 2,
            "weight": 0.4,
            "notional": 20000,
            "price": 18332.7,
            "duration": 2,
            "modified_duration": 1.956947,
            "dv01": 3.587612,
            "convexity": 4.787053
          },
          {
            "rung": 2,
            "maturity_years": 6,
            "weight": 0.6,
            "notional": 30000,
            "price": 30233.62,
            "duration": 5.293982,
            "modified_duration": 5.174958,
            "dv01": 15.645773,
            "convexity": 31.473683
          }
        ],
        "portfolio": {
          "weighted_duration": 3.976389,
          "weighted_modified_duration": 3.887754,
          "weighted_dv01": 10.822509,
          "weighted_convexity": 20.799031
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 2 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (hold_to_maturity): every coupon payment and every maturing rung's principal are held as cash earning 0% after receipt — nothing is reinvested and nothing is rolled into other rungs. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung's contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "f174dac58fedb3500de73fb00e6564217f0df4ec12a76c3fa1e3877182b73388"
    },
    {
      "name": "F5_roll_to_longest_rung",
      "policy_parameters": {
        "notional": 250000,
        "periods_per_year": 2,
        "reinvestment_assumption": "roll_to_longest_rung",
        "rungs": [
          {
            "maturity_years": 1,
            "coupon_rate_pct": 4,
            "yield_pct": 4.1,
            "target_weight": 0.25
          },
          {
            "maturity_years": 10,
            "coupon_rate_pct": 5,
            "yield_pct": 4.9,
            "target_weight": 0.75
          }
        ]
      },
      "output_payload": {
        "notional": 250000,
        "periods_per_year": 2,
        "reinvestment_assumption": "roll_to_longest_rung",
        "num_rungs": 2,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 1,
            "weight": 0.25,
            "notional": 62500,
            "price": 62439.37,
            "duration": 0.990191,
            "modified_duration": 0.9703,
            "dv01": 6.058493,
            "convexity": 1.421504
          },
          {
            "rung": 2,
            "maturity_years": 10,
            "weight": 0.75,
            "notional": 187500,
            "price": 188968.41,
            "duration": 7.998729,
            "modified_duration": 7.807446,
            "dv01": 147.536094,
            "convexity": 73.813105
          }
        ],
        "portfolio": {
          "weighted_duration": 6.246594,
          "weighted_modified_duration": 6.09816,
          "weighted_dv01": 112.166694,
          "weighted_convexity": 55.715204
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 2 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (roll_to_longest_rung): every coupon payment and every maturing rung’s principal are assumed reinvested at the longest rung’s yield (4.9% nominal, 10 years) as its cash flows are received, keeping the ladder fully invested. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung’s contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "523b88a74fdb882d99d5a71db37c0a5d400c61ae0adea9f78ddb0f3fb711bacb"
    },
    {
      "name": "F6_monthly_periods",
      "policy_parameters": {
        "notional": 120000,
        "periods_per_year": 12,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 0.5,
            "coupon_rate_pct": 3.9,
            "yield_pct": 4,
            "target_weight": 0.5
          },
          {
            "maturity_years": 2,
            "coupon_rate_pct": 4.3,
            "yield_pct": 4.35,
            "target_weight": 0.5
          }
        ]
      },
      "output_payload": {
        "notional": 120000,
        "periods_per_year": 12,
        "reinvestment_assumption": "hold_to_maturity",
        "num_rungs": 2,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 0.5,
            "weight": 0.5,
            "notional": 60000,
            "price": 59970.35,
            "duration": 0.495967,
            "modified_duration": 0.494319,
            "dv01": 2.964449,
            "convexity": 0.286618
          },
          {
            "rung": 2,
            "maturity_years": 2,
            "weight": 0.5,
            "notional": 60000,
            "price": 59942.64,
            "duration": 1.919939,
            "modified_duration": 1.913004,
            "dv01": 11.467052,
            "convexity": 3.916562
          }
        ],
        "portfolio": {
          "weighted_duration": 1.207953,
          "weighted_modified_duration": 1.203662,
          "weighted_dv01": 7.215751,
          "weighted_convexity": 2.10159
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 12 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (hold_to_maturity): every coupon payment and every maturing rung's principal are held as cash earning 0% after receipt — nothing is reinvested and nothing is rolled into other rungs. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung's contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "0fd2e650f7786f312675ab58bacbd9e2391093d0e16351f29d941ac499d017f2"
    },
    {
      "name": "F7_scaled_notional_2x_of_F2",
      "policy_parameters": {
        "notional": 600000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "rungs": [
          {
            "maturity_years": 1,
            "coupon_rate_pct": 4,
            "yield_pct": 4.1,
            "target_weight": 0.3333333333333333
          },
          {
            "maturity_years": 3,
            "coupon_rate_pct": 4.25,
            "yield_pct": 4.3,
            "target_weight": 0.3333333333333333
          },
          {
            "maturity_years": 5,
            "coupon_rate_pct": 4.5,
            "yield_pct": 4.5,
            "target_weight": 0.3333333333333333
          }
        ]
      },
      "output_payload": {
        "notional": 600000,
        "periods_per_year": 2,
        "reinvestment_assumption": "hold_to_maturity",
        "num_rungs": 3,
        "ladder": [
          {
            "rung": 1,
            "maturity_years": 1,
            "weight": 0.3333333333333333,
            "notional": 200000,
            "price": 199805.99,
            "duration": 0.990191,
            "modified_duration": 0.9703,
            "dv01": 19.387179,
            "convexity": 1.421504
          },
          {
            "rung": 2,
            "maturity_years": 3,
            "weight": 0.3333333333333333,
            "notional": 200000,
            "price": 199721.34,
            "duration": 2.848078,
            "modified_duration": 2.788133,
            "dv01": 55.684964,
            "convexity": 9.385603
          },
          {
            "rung": 3,
            "maturity_years": 5,
            "weight": 0.3333333333333333,
            "notional": 200000,
            "price": 200000,
            "duration": 4.532853,
            "modified_duration": 4.433108,
            "dv01": 88.662168,
            "convexity": 23.050364
          }
        ],
        "portfolio": {
          "weighted_duration": 2.790374,
          "weighted_modified_duration": 2.730514,
          "weighted_dv01": 54.578104,
          "weighted_convexity": 11.285824
        },
        "assumptions": [
          "Schedule assumption: each rung is priced as an even-period bullet bond with 2 coupon period(s) per year — a fixed coupon of coupon_rate_pct/100 of face paid every period and face repaid with the final coupon; no odd first coupon, no stub periods, and no day-count accrual nuances are modeled.",
          "Yield assumption: each rung's yield_pct is a flat yield to maturity applied to all of that rung's cash flows; there is no credit spread, no forward curve, and no term-structure interpolation across rungs.",
          "Instrument assumption: all rungs are non-callable bullet bonds held to maturity — no call or put features, no default, no early sale, and no live market data are used.",
          "Reinvestment assumption (hold_to_maturity): every coupon payment and every maturing rung's principal are held as cash earning 0% after receipt — nothing is reinvested and nothing is rolled into other rungs. The duration, DV01 and convexity reported per rung and for the portfolio are computed on each rung's contractual bond cash flows only and do not depend on this assumption.",
          "Portfolio aggregation assumption: portfolio weighted_duration, weighted_modified_duration, weighted_dv01 and weighted_convexity are target_weight-weighted averages of the per-rung figures; no diversification or cross-rung offset effects are modeled."
        ],
        "regulatory_basis": "Standard fixed-income risk analytics (Macaulay/modified duration, DV01 by central-difference reprice, closed-form convexity) applied rung-by-rung over a target-weight bond ladder (Fabozzi, Bond Markets)",
        "note": "Per-rung maths are the same formulas as compute_bond_duration (art-329), compute_dv01 (art-330) and compute_convexity (art-331) applied at each rung’s notional = notional * target_weight; parity is asserted by the art-705 parity gate. Exclusions: no credit spread, no call features, flat yield per rung, no live data."
      },
      "golden_hash": "ad7adeedc9ca1cf903be24f6bc7fd0015a907f0130a291e3a06da9b82ab4e476"
    },
    {
      "name": "F8_invalid_reinvestment_enum_refused",
      "policy_parameters": {
        "notional": 100000,
        "periods_per_year": 2,
        "reinvestment_assumption": "reinvest_at_front_rung",
        "rungs": [
          {
            "maturity_years": 3,
            "coupon_rate_pct": 4.25,
            "yield_pct": 4.3,
            "target_weight": 1
          }
        ]
      },
      "output_payload": {
        "error": "reinvestment_assumption_invalid",
        "detail": "reinvestment_assumption must be one of 'hold_to_maturity' or 'roll_to_longest_rung'; got \"reinvest_at_front_rung\".",
        "domain_errors": [
          {
            "code": "REINVESTMENT_ASSUMPTION_INVALID",
            "text": "reinvestment_assumption must be one of 'hold_to_maturity' or 'roll_to_longest_rung'; got \"reinvest_at_front_rung\"."
          }
        ],
        "ladder": null,
        "portfolio": null,
        "assumptions": []
      },
      "golden_hash": "c84776d01312ff2bdf9a1bd65e0692877f7681709f09646e6c58c4d56cdc3d8b"
    }
  ]
}
