sourcecode 5.9.7__py3-none-any.whl → 5.9.8__py3-none-any.whl

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.

Potentially problematic release.


This version of sourcecode might be problematic. Click here for more details.

sourcecode/__init__.py CHANGED
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "5.9.7"
7
+ __version__ = "5.9.8"
@@ -1,5 +1,5 @@
1
1
  """Generated at build time by hatch_build.py. Do not edit (AUD-592-D04)."""
2
2
 
3
- BUILD_COMMIT = 'ba9b9e9f310b129eb400a4c6e82b4d21f52366b8'
4
- CLOSURE_PROVENANCE = {'AUD-611-B05': {'commit': '', 'status': 'uncited'}, 'AUD-611-B06': {'commit': '', 'status': 'uncited'}, 'AUD-611-B07': {'commit': '', 'status': 'uncited'}, 'AUD-611-B08': {'commit': '', 'status': 'uncited'}, 'AUD-611-B09': {'commit': '', 'status': 'uncited'}, 'AUD-611-B10': {'commit': '', 'status': 'uncited'}, 'AUD-611-B11': {'commit': '', 'status': 'uncited'}, 'Window': {'commit': '', 'status': 'uncited'}, '`ASK-FIELD-01`': {'commit': '829f9fa', 'status': 'present'}, '`ASK-FIELD-02`': {'commit': '6a659fa', 'status': 'present'}, '`ASK-FIELD-03`': {'commit': '55b0d51', 'status': 'present'}, '`AUD-588-F05`': {'commit': '470e4a4', 'status': 'present'}, '`AUD-590-B01` / `B-01`, `F-01`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B02` / `B-02`, `F-02`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B03` / `B-03`, `F-03`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B04` / `B-04`, `F-04`': {'commit': '', 'status': 'uncited'}, '`AUD-590-R01` / `R-01`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A01` / `A-1`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A02` / `A-2`, `A-4`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A03` / `A-3`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A05` / `A-5`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A06` / `A-6`, `A-7`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A08` / `A-8`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A09` / `A-9`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A10` / `A-10`': {'commit': '', 'status': 'uncited'}, '`AUD-592-A02` / `A-1` second half, `§12.5`': {'commit': '63f3d61', 'status': 'present'}, '`AUD-592-B01` / `B-8`': {'commit': '8329614', 'status': 'present'}, '`AUD-592-D01` / `D-1`': {'commit': '0f8e03f', 'status': 'present'}, '`AUD-592-D02` / `D-2`': {'commit': '1d3db4d', 'status': 'present'}, '`AUD-592-D03` / `D-3`': {'commit': 'f28fe40', 'status': 'present'}, '`AUD-592-R01` / `A-1`': {'commit': '216025f', 'status': 'present'}, '`AUD-592-R02` / `N-4`, reopens `AUD-513-N04`': {'commit': 'ec3050d', 'status': 'present'}, '`AUD-593-N01` / `N-01`': {'commit': 'dd6a706', 'status': 'present'}, '`AUD-593-N02` / `N-02`': {'commit': 'f539787', 'status': 'present'}, '`AUD-593-N03` / `N-03`': {'commit': '1dd0b1c', 'status': 'present'}, '`AUD-593-N05` / `N-05`': {'commit': 'aa89388', 'status': 'present'}, '`AUD-593-N06` / `N-06`': {'commit': 'aa584a6', 'status': 'present'}, '`AUD-594-N04` / `D-5`, disclosure half of `B-3`': {'commit': 'a0060b7', 'status': 'present'}, '`AUD-594-X01` / `A-1`, residual of `AUD-593-N03`': {'commit': 'dd222b9', 'status': 'present'}, '`AUD-594-X02` / `A-1` second half': {'commit': '1193937', 'status': 'present'}, '`AUD-594-X03` / `X-03`, residual of `AUD-593-N01`': {'commit': 'e89e8f0', 'status': 'present'}, '`AUD-594-X04`': {'commit': '05b8cc9', 'status': 'present'}, '`AUD-595-A02` / `N-5`, advisory half of `AUD-588-B11`': {'commit': '3e15227', 'status': 'present'}, '`AUD-595-A03` / `B-6` exit-code half': {'commit': 'ab7285f', 'status': 'present'}, '`AUD-595-A05`': {'commit': 'e0b3d10', 'status': 'present'}, '`AUD-595-A07`, narrow half of `AUD-592-A02`': {'commit': 'cc15177', 'status': 'present'}, '`AUD-595-B01` / §B': {'commit': 'b77a1ad', 'status': 'present'}, '`AUD-595-Q01`': {'commit': '91a6566', 'status': 'present'}, '`AUD-596-A01` / `ASK-DET-001`': {'commit': 'fa508b4', 'status': 'present'}, '`AUD-596-A02` / `ASK-SELF-001`': {'commit': '4dfadc8', 'status': 'present'}, '`AUD-596-A03` / `ASK-C1-001`': {'commit': 'bffa3a6', 'status': 'present'}, '`AUD-596-A04` / `ASK-UX-003` + `ASK-UX-004`': {'commit': 'f0aac3c', 'status': 'present'}, '`AUD-596-B01` / `B-01`, harder witness for `BUG-6`': {'commit': '567d09d', 'status': 'present'}, '`AUD-596-B02` / `B-02`, class residual of `R2`': {'commit': '', 'status': 'uncited'}, '`AUD-596-B03` / `B-03`': {'commit': 'a8cb814', 'status': 'present'}, '`AUD-596-B06` / `B-06`': {'commit': '8107927', 'status': 'present'}, '`AUD-596-B07` / `B-07`, class residual of `AUD-592-R02`': {'commit': 'e060485', 'status': 'present'}, '`AUD-596-B09` / `B-09`': {'commit': '5b8146c', 'status': 'present'}, '`AUD-596-B10` / `B-10`': {'commit': '5cb994d', 'status': 'present'}, '`AUD-596-B16` / `B-16`': {'commit': '1507f69', 'status': 'present'}, '`AUD-596-D01` / `B-13` + `B-14`': {'commit': '0b1bdf0', 'status': 'present'}, '`AUD-596-D02` / `B-08`, residual of `AUD-594-N04`': {'commit': 'e7f73c3', 'status': 'present'}, '`AUD-596-D03` / `ASK-AGT-001`': {'commit': '8c46967', 'status': 'present'}, '`AUD-596-D04` / `B-18`': {'commit': '040f027', 'status': 'present'}, '`AUD-596-D05` / `B-19`': {'commit': 'fd2bf68', 'status': 'present'}, '`AUD-596-D06` / `B-20`': {'commit': '784cd83', 'status': 'present'}, '`AUD-596-D07` / `B-17`, half refuted': {'commit': 'c3ff822', 'status': 'present'}, '`AUD-596-D08` / `B-22`, class residual of `AUD-591-A06`': {'commit': 'b396c6a', 'status': 'present'}, '`AUD-596-D09` / `B-23`, surviving half of `B26`': {'commit': 'fd3d63f', 'status': 'present'}, '`AUD-596-D10` / `B-29`': {'commit': '', 'status': 'uncited'}, '`AUD-596-D11` / `ASK-UX-005`': {'commit': 'f4b4f77', 'status': 'present'}, '`AUD-596-D12` — six hints that send the reader back to the error': {'commit': '498df44', 'status': 'present'}, '`AUD-596-D13` / `B-28`': {'commit': '1014c72', 'status': 'present'}, '`AUD-596-D14` / `B-15`, narrow half of `B20`': {'commit': '10f2827', 'status': 'present'}, '`AUD-596-R01` / `B-05`': {'commit': '', 'status': 'uncited'}, '`AUD-596-X01` / `ASK-GATE-001`, gating half of `B24`': {'commit': 'e59c655', 'status': 'present'}, '`AUD-596-X02` / `ASK-UX-001` + `ASK-UX-002` + `B-21`': {'commit': 'f6ebf50', 'status': 'present'}, '`AUD-597-A01` / `ASK-UX-001` + `N-01`': {'commit': 'f8cf061', 'status': 'present'}, '`AUD-597-A02` / `ASK-UX-008` + `ASK-DOC-002`': {'commit': '9d47a4c', 'status': 'present'}, '`AUD-597-A03` / `ASK-DET-001`': {'commit': '4c7622a', 'status': 'present'}, '`AUD-597-A04` / `ASK-LEDGER-001`': {'commit': '46fb870', 'status': 'present'}, '`AUD-597-D01` / `B-04`': {'commit': '1094e6a', 'status': 'present'}, '`AUD-597-D02` / `ASK-DOC-001`': {'commit': 'ecb1bb7', 'status': 'present'}, '`AUD-597-D03` / `N-06`': {'commit': '9784333', 'status': 'present'}, '`AUD-597-D04` / `N-05`': {'commit': 'e51c087', 'status': 'present'}, '`AUD-597-D05` / `N-04`, fourth appearance of `C4-27`': {'commit': '9cccc15', 'status': 'present'}, '`AUD-597-D06` / `ASK-CLI-001`': {'commit': '178aa6d', 'status': 'present'}, '`AUD-597-D07` / `N-03`': {'commit': '9245e35', 'status': 'present'}, '`AUD-597-R01` / `ASK-PERF-001`': {'commit': '6910054', 'status': 'present'}, '`AUD-597-R02` / `ASK-ENC-001`': {'commit': 'ce6dac1', 'status': 'present'}, '`AUD-597-R03` / `ASK-UX-002`': {'commit': 'c57e50b', 'status': 'present'}, '`AUD-597-X01` / `ASK-BUILD-001` + `ASK-META-001` / `B-12`': {'commit': '354338b', 'status': 'present'}, '`AUD-598-B01` / `ASK-META-001`': {'commit': 'b2f7c65', 'status': 'present'}, '`AUD-598-B02` / `ASK-UX-002`': {'commit': '56a4bf7', 'status': 'present'}, '`AUD-598-B03` / `B-11`': {'commit': 'c63cb24', 'status': 'present'}, '`AUD-598-B04` / `N-02`': {'commit': '187937f', 'status': 'present'}, '`AUD-598-R01` / `ASK-PERF-002`': {'commit': '', 'status': 'uncited'}, '`AUD-598-X01` / `N-01` + `B-13` + `B-14` + `B-29` + `N-06`': {'commit': '6f2f5a4', 'status': 'present'}, '`AUD-600-B01` / `P-01`': {'commit': '366ffed', 'status': 'present'}, '`AUD-600-B02` / `P-02` + `ASK-PACK-002`': {'commit': '2a814c3', 'status': 'present'}, '`AUD-600-B03` / `ASK-PACK-001`': {'commit': '452f2a0', 'status': 'present'}, '`AUD-600-D01`': {'commit': '1224e1b', 'status': 'present'}, '`AUD-600-D02`': {'commit': 'eab8172', 'status': 'present'}, '`AUD-600-R01` / `R-01`': {'commit': '88add64', 'status': 'present'}, '`AUD-601-B01` / `N-02`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-B02` / `ASK-PACK-004`': {'commit': '', 'status': 'uncited'}, '`AUD-601-D01` / `N-01`, `ASK-UX-001`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-D02` / `B-13`, `B-14`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-M01` / `B-26`, `B-27` retracted': {'commit': '', 'status': 'uncited'}, '`AUD-601-R01` / `R-02`': {'commit': '', 'status': 'uncited'}, '`B-3`': {'commit': '773268d', 'status': 'present'}, '`B-6`': {'commit': '17c6e06', 'status': 'present'}, '`B-8`': {'commit': '8329614', 'status': 'present'}, '`BUG-3` / `443b345`': {'commit': '', 'status': 'uncited'}, '`BUG-4a` / `AUD-588-B11` residual': {'commit': '24b4185', 'status': 'present'}, '`BUG-4b` / `AUD-588-B11` residual': {'commit': '0376350', 'status': 'present'}, '`E-39`, class residual of `AUD-593-N06`': {'commit': '25fc11f', 'status': 'present'}, '`N-5`': {'commit': 'c68083f', 'status': 'present'}, '`N-7`': {'commit': '082e9de', 'status': 'present'}, '`R-1`': {'commit': '424fb1c', 'status': 'present'}, '`R-2`': {'commit': '5158b92', 'status': 'present'}, '`R-3`': {'commit': '88aec04', 'status': 'present'}, '`R-4`': {'commit': '04fd04f', 'status': 'present'}}
5
- CLOSURE_COVERAGE = {'closed_rows': 123, 'present': 91, 'absent': 0, 'unresolved': 0, 'uncited': 32, 'unknown': 0}
3
+ BUILD_COMMIT = 'ac7c82deb24ccbea4ce12cb79d08c1d2f6461ff2'
4
+ CLOSURE_PROVENANCE = {'AUD-611-B05': {'commit': '', 'status': 'uncited'}, 'AUD-611-B06': {'commit': '', 'status': 'uncited'}, 'AUD-611-B07': {'commit': '', 'status': 'uncited'}, 'AUD-611-B08': {'commit': '', 'status': 'uncited'}, 'AUD-611-B09': {'commit': '', 'status': 'uncited'}, 'AUD-611-B10': {'commit': '', 'status': 'uncited'}, 'AUD-611-B11': {'commit': '', 'status': 'uncited'}, 'AUD-612-07': {'commit': '', 'status': 'uncited'}, 'AUD-612-09': {'commit': '', 'status': 'uncited'}, 'AUD-612-14': {'commit': '', 'status': 'uncited'}, 'AUD-612-B03': {'commit': '', 'status': 'uncited'}, 'AUD-612-B07': {'commit': '', 'status': 'uncited'}, 'AUD-612-B13': {'commit': '', 'status': 'uncited'}, 'AUD-612-E': {'commit': '', 'status': 'uncited'}, 'AUD-612-G': {'commit': '', 'status': 'uncited'}, 'AUD-612-I': {'commit': '', 'status': 'uncited'}, 'AUD-612-K': {'commit': '', 'status': 'uncited'}, 'AUD-612-M': {'commit': '', 'status': 'uncited'}, 'AUD-612-R': {'commit': '', 'status': 'uncited'}, 'Window': {'commit': '', 'status': 'uncited'}, '`ASK-FIELD-01`': {'commit': '829f9fa', 'status': 'present'}, '`ASK-FIELD-02`': {'commit': '6a659fa', 'status': 'present'}, '`ASK-FIELD-03`': {'commit': '55b0d51', 'status': 'present'}, '`AUD-588-F05`': {'commit': '470e4a4', 'status': 'present'}, '`AUD-590-B01` / `B-01`, `F-01`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B02` / `B-02`, `F-02`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B03` / `B-03`, `F-03`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B04` / `B-04`, `F-04`': {'commit': '', 'status': 'uncited'}, '`AUD-590-R01` / `R-01`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A01` / `A-1`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A02` / `A-2`, `A-4`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A03` / `A-3`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A05` / `A-5`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A06` / `A-6`, `A-7`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A08` / `A-8`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A09` / `A-9`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A10` / `A-10`': {'commit': '', 'status': 'uncited'}, '`AUD-592-A02` / `A-1` second half, `§12.5`': {'commit': '63f3d61', 'status': 'present'}, '`AUD-592-B01` / `B-8`': {'commit': '8329614', 'status': 'present'}, '`AUD-592-D01` / `D-1`': {'commit': '0f8e03f', 'status': 'present'}, '`AUD-592-D02` / `D-2`': {'commit': '1d3db4d', 'status': 'present'}, '`AUD-592-D03` / `D-3`': {'commit': 'f28fe40', 'status': 'present'}, '`AUD-592-R01` / `A-1`': {'commit': '216025f', 'status': 'present'}, '`AUD-592-R02` / `N-4`, reopens `AUD-513-N04`': {'commit': 'ec3050d', 'status': 'present'}, '`AUD-593-N01` / `N-01`': {'commit': 'dd6a706', 'status': 'present'}, '`AUD-593-N02` / `N-02`': {'commit': 'f539787', 'status': 'present'}, '`AUD-593-N03` / `N-03`': {'commit': '1dd0b1c', 'status': 'present'}, '`AUD-593-N05` / `N-05`': {'commit': 'aa89388', 'status': 'present'}, '`AUD-593-N06` / `N-06`': {'commit': 'aa584a6', 'status': 'present'}, '`AUD-594-N04` / `D-5`, disclosure half of `B-3`': {'commit': 'a0060b7', 'status': 'present'}, '`AUD-594-X01` / `A-1`, residual of `AUD-593-N03`': {'commit': 'dd222b9', 'status': 'present'}, '`AUD-594-X02` / `A-1` second half': {'commit': '1193937', 'status': 'present'}, '`AUD-594-X03` / `X-03`, residual of `AUD-593-N01`': {'commit': 'e89e8f0', 'status': 'present'}, '`AUD-594-X04`': {'commit': '05b8cc9', 'status': 'present'}, '`AUD-595-A02` / `N-5`, advisory half of `AUD-588-B11`': {'commit': '3e15227', 'status': 'present'}, '`AUD-595-A03` / `B-6` exit-code half': {'commit': 'ab7285f', 'status': 'present'}, '`AUD-595-A05`': {'commit': 'e0b3d10', 'status': 'present'}, '`AUD-595-A07`, narrow half of `AUD-592-A02`': {'commit': 'cc15177', 'status': 'present'}, '`AUD-595-B01` / §B': {'commit': 'b77a1ad', 'status': 'present'}, '`AUD-595-Q01`': {'commit': '91a6566', 'status': 'present'}, '`AUD-596-A01` / `ASK-DET-001`': {'commit': 'fa508b4', 'status': 'present'}, '`AUD-596-A02` / `ASK-SELF-001`': {'commit': '4dfadc8', 'status': 'present'}, '`AUD-596-A03` / `ASK-C1-001`': {'commit': 'bffa3a6', 'status': 'present'}, '`AUD-596-A04` / `ASK-UX-003` + `ASK-UX-004`': {'commit': 'f0aac3c', 'status': 'present'}, '`AUD-596-B01` / `B-01`, harder witness for `BUG-6`': {'commit': '567d09d', 'status': 'present'}, '`AUD-596-B02` / `B-02`, class residual of `R2`': {'commit': '', 'status': 'uncited'}, '`AUD-596-B03` / `B-03`': {'commit': 'a8cb814', 'status': 'present'}, '`AUD-596-B06` / `B-06`': {'commit': '8107927', 'status': 'present'}, '`AUD-596-B07` / `B-07`, class residual of `AUD-592-R02`': {'commit': 'e060485', 'status': 'present'}, '`AUD-596-B09` / `B-09`': {'commit': '5b8146c', 'status': 'present'}, '`AUD-596-B10` / `B-10`': {'commit': '5cb994d', 'status': 'present'}, '`AUD-596-B16` / `B-16`': {'commit': '1507f69', 'status': 'present'}, '`AUD-596-D01` / `B-13` + `B-14`': {'commit': '0b1bdf0', 'status': 'present'}, '`AUD-596-D02` / `B-08`, residual of `AUD-594-N04`': {'commit': 'e7f73c3', 'status': 'present'}, '`AUD-596-D03` / `ASK-AGT-001`': {'commit': '8c46967', 'status': 'present'}, '`AUD-596-D04` / `B-18`': {'commit': '040f027', 'status': 'present'}, '`AUD-596-D05` / `B-19`': {'commit': 'fd2bf68', 'status': 'present'}, '`AUD-596-D06` / `B-20`': {'commit': '784cd83', 'status': 'present'}, '`AUD-596-D07` / `B-17`, half refuted': {'commit': 'c3ff822', 'status': 'present'}, '`AUD-596-D08` / `B-22`, class residual of `AUD-591-A06`': {'commit': 'b396c6a', 'status': 'present'}, '`AUD-596-D09` / `B-23`, surviving half of `B26`': {'commit': 'fd3d63f', 'status': 'present'}, '`AUD-596-D10` / `B-29`': {'commit': '', 'status': 'uncited'}, '`AUD-596-D11` / `ASK-UX-005`': {'commit': 'f4b4f77', 'status': 'present'}, '`AUD-596-D12` — six hints that send the reader back to the error': {'commit': '498df44', 'status': 'present'}, '`AUD-596-D13` / `B-28`': {'commit': '1014c72', 'status': 'present'}, '`AUD-596-D14` / `B-15`, narrow half of `B20`': {'commit': '10f2827', 'status': 'present'}, '`AUD-596-R01` / `B-05`': {'commit': '', 'status': 'uncited'}, '`AUD-596-X01` / `ASK-GATE-001`, gating half of `B24`': {'commit': 'e59c655', 'status': 'present'}, '`AUD-596-X02` / `ASK-UX-001` + `ASK-UX-002` + `B-21`': {'commit': 'f6ebf50', 'status': 'present'}, '`AUD-597-A01` / `ASK-UX-001` + `N-01`': {'commit': 'f8cf061', 'status': 'present'}, '`AUD-597-A02` / `ASK-UX-008` + `ASK-DOC-002`': {'commit': '9d47a4c', 'status': 'present'}, '`AUD-597-A03` / `ASK-DET-001`': {'commit': '4c7622a', 'status': 'present'}, '`AUD-597-A04` / `ASK-LEDGER-001`': {'commit': '46fb870', 'status': 'present'}, '`AUD-597-D01` / `B-04`': {'commit': '1094e6a', 'status': 'present'}, '`AUD-597-D02` / `ASK-DOC-001`': {'commit': 'ecb1bb7', 'status': 'present'}, '`AUD-597-D03` / `N-06`': {'commit': '9784333', 'status': 'present'}, '`AUD-597-D04` / `N-05`': {'commit': 'e51c087', 'status': 'present'}, '`AUD-597-D05` / `N-04`, fourth appearance of `C4-27`': {'commit': '9cccc15', 'status': 'present'}, '`AUD-597-D06` / `ASK-CLI-001`': {'commit': '178aa6d', 'status': 'present'}, '`AUD-597-D07` / `N-03`': {'commit': '9245e35', 'status': 'present'}, '`AUD-597-R01` / `ASK-PERF-001`': {'commit': '6910054', 'status': 'present'}, '`AUD-597-R02` / `ASK-ENC-001`': {'commit': 'ce6dac1', 'status': 'present'}, '`AUD-597-R03` / `ASK-UX-002`': {'commit': 'c57e50b', 'status': 'present'}, '`AUD-597-X01` / `ASK-BUILD-001` + `ASK-META-001` / `B-12`': {'commit': '354338b', 'status': 'present'}, '`AUD-598-B01` / `ASK-META-001`': {'commit': 'b2f7c65', 'status': 'present'}, '`AUD-598-B02` / `ASK-UX-002`': {'commit': '56a4bf7', 'status': 'present'}, '`AUD-598-B03` / `B-11`': {'commit': 'c63cb24', 'status': 'present'}, '`AUD-598-B04` / `N-02`': {'commit': '187937f', 'status': 'present'}, '`AUD-598-R01` / `ASK-PERF-002`': {'commit': '', 'status': 'uncited'}, '`AUD-598-X01` / `N-01` + `B-13` + `B-14` + `B-29` + `N-06`': {'commit': '6f2f5a4', 'status': 'present'}, '`AUD-600-B01` / `P-01`': {'commit': '366ffed', 'status': 'present'}, '`AUD-600-B02` / `P-02` + `ASK-PACK-002`': {'commit': '2a814c3', 'status': 'present'}, '`AUD-600-B03` / `ASK-PACK-001`': {'commit': '452f2a0', 'status': 'present'}, '`AUD-600-D01`': {'commit': '1224e1b', 'status': 'present'}, '`AUD-600-D02`': {'commit': 'eab8172', 'status': 'present'}, '`AUD-600-R01` / `R-01`': {'commit': '88add64', 'status': 'present'}, '`AUD-601-B01` / `N-02`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-B02` / `ASK-PACK-004`': {'commit': '', 'status': 'uncited'}, '`AUD-601-D01` / `N-01`, `ASK-UX-001`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-D02` / `B-13`, `B-14`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-M01` / `B-26`, `B-27` retracted': {'commit': '', 'status': 'uncited'}, '`AUD-601-R01` / `R-02`': {'commit': '', 'status': 'uncited'}, '`B-3`': {'commit': '773268d', 'status': 'present'}, '`B-6`': {'commit': '17c6e06', 'status': 'present'}, '`B-8`': {'commit': '8329614', 'status': 'present'}, '`BUG-3` / `443b345`': {'commit': '', 'status': 'uncited'}, '`BUG-4a` / `AUD-588-B11` residual': {'commit': '24b4185', 'status': 'present'}, '`BUG-4b` / `AUD-588-B11` residual': {'commit': '0376350', 'status': 'present'}, '`E-39`, class residual of `AUD-593-N06`': {'commit': '25fc11f', 'status': 'present'}, '`N-5`': {'commit': 'c68083f', 'status': 'present'}, '`N-7`': {'commit': '082e9de', 'status': 'present'}, '`R-1`': {'commit': '424fb1c', 'status': 'present'}, '`R-2`': {'commit': '5158b92', 'status': 'present'}, '`R-3`': {'commit': '88aec04', 'status': 'present'}, '`R-4`': {'commit': '04fd04f', 'status': 'present'}}
5
+ CLOSURE_COVERAGE = {'closed_rows': 135, 'present': 91, 'absent': 0, 'unresolved': 0, 'uncited': 44, 'unknown': 0}
@@ -71,6 +71,35 @@ Commercially, the audit supports normal repositories up to several thousand
71
71
  files and keeps a provisional $35-50/developer/month range, but B01/B02 block
72
72
  annual-grade reliability and enterprise-scale positioning until resolved.
73
73
 
74
+ **External audit intake `AUD-612`, re-audit of release 5.9.7 — 2026-08-27.**
75
+ The external scope covered roughly 130 new invocations across three forks and direct
76
+ retests of all AUD-611 items. It reports five clean forks, no target writes, commits
77
+ or task-kills, and a score of **7.8/10**. It confirms B05, B06, B08, B09, B10 and B11,
78
+ and reports B01 fixed in its own matrix; B01 remains release-artifact verification
79
+ because the prior external round reproduced it. The new queue is:
80
+
81
+ | ID | Severity | Status | Evidence / closure boundary |
82
+ |---|---:|---|---|
83
+ | AUD-612-B02 | Critical | open | `tutorials` root compact still timed out after 300-311s with zero stdout; warning proves activity, not completion. Define scale, deadline and partial-diagnostic contracts. |
84
+ | AUD-612-B03 | High | closed | YAML cache-hit delivery now publishes `_cache.cache_source` and `timing_ms.served_from_cache` consistently; TeaVM YAML smoke plus the direct cache-hit seam regression pass. A real L2 benchmark remains follow-up because this environment rebuilt both runs. |
85
+ | AUD-612-B04 | High | partial | Each `selftest` row now has configurable 120 s default timeout and structured timeout diagnostics/code 75; valid-row scale latency remains open for profiling. Dedicated TeaVM timeout contract regression passes. |
86
+ | AUD-612-B07 | Medium | closed | `pr-impact --since` now resolves refs through the shared authority and publishes `GIT_REF_NOT_FOUND`; dedicated TeaVM and existing Git-ref regressions pass. |
87
+ | AUD-612-B13 | Medium | closed/no-repro | Controlled TeaVM campaign: 30/30 `retrieve endpoint-security --endpoint /` executions completed with exit 0, valid JSON, no errors and stable content identity after cache warm-up. Reopen on a new correlated failure. |
88
+ | AUD-612-L | High | open | `audit-report --format markdown` timed out at 420s/500s, 2/2, after ~228s in 5.9.6. Performance regression remains open; the one-shot heartbeat sub-issue is mitigated by repeated warnings. |
89
+ | AUD-612-K | Medium | closed | Pack orchestration now streams child stderr, forwarding inherited `ASK_PROGRESS=1` progress while preserving aggregate stdout JSON. Dedicated TeaVM gate regression passes. |
90
+ | AUD-612-M | Medium | closed | `explain` missing-class failures now use structured `INVALID_INPUT` stderr and `exit 1`; dedicated TeaVM regression passes. |
91
+ | AUD-612-E | Medium | closed | The events branch now applies `_exit_on_unresolved_target`; missing event symbols return `not_found` with `exit 1`. TeaVM regression passes. |
92
+ | AUD-612-G | Medium | closed | `review-pr` runtime failures and `activate` failures now publish the shared `error.code` envelope on stderr; stdout remains reserved for valid results. `no_diff` remains the intentional successful `no_changes` result. Dedicated TeaVM and contract tests pass. |
93
+ | AUD-612-I | Medium | closed | Removed the residual `~10K` wording from the large-output warning; help, runtime warning and compact payload consistently describe a snapshot-dependent subset with explicit `full_available` metadata. Dedicated TeaVM regression passes. |
94
+ | AUD-612-07 | Low | closed | Missing single tokens close to a registered command now use command admission with a nearest-command suggestion; existing paths retain implicit root-scan behavior. Dedicated TeaVM regression passes. |
95
+ | AUD-612-09 | Medium | closed | `--files -` is documented and enforced as a newline-delimited changed-path list; raw unified diffs fail with an `--name-only` conversion hint. Dedicated TeaVM regressions pass. |
96
+ | AUD-612-14 | Medium | closed | The current population is 104 CLI leaves versus 110 MCP tools, explicitly decomposed as 101 runtime-derived plus 9 native orchestration tools; `mcp list-tools --json` matches and the relationship is published. Existing TeaVM-backed population regression passes. |
97
+ | AUD-612-R | Medium | closed | README, English guide and Spanish manual document that `rename-class` requires `--from/--to`, the old positional syntax is unsupported, and `--dry-run` is the migration safety step. TeaVM dry-run verification passes. |
98
+
99
+ Commercially, normal repositories up to about 4,000 files remain viable at a provisional
100
+ $40-55/developer/month. B02, B04 and L block annual CI-gating and extreme-monorepo claims;
101
+ B03, K, M and G weaken machine-consumable evidence.
102
+
74
103
  **External audit intake `AUD-610`, release 5.9.3 — 2026-08-27.** The attached
75
104
  report scored the build **7.2/10** after five parallel batches and approximately
76
105
  120 invocations. It verified a clean target repository, no Java-file changes,
@@ -46,16 +46,16 @@ CLI commands — impact, endpoints, spring-audit, explain, … each a pro
46
46
  The key idea: the extraction is **content-addressed**. Commands reuse the parse cache and,
47
47
  where their analysed scope matches, the shared Canonical IR; `ask cache model` names what a
48
48
  warm buys for each command rather than implying that every projection costs the same. In
49
- 5.9.7, `validation` enters through that shared CIR and `data-exposure` reuses one semantic
49
+ 5.9.8, `validation` enters through that shared CIR and `data-exposure` reuses one semantic
50
50
  model across all declared label seeds. (The extraction and consumption contract is fixed in
51
51
  the architecture ADRs 0001–0004 under `docs/architecture/`.)
52
52
 
53
53
  The current external pack audit intake is tracked in
54
54
  [`AUDIT-2026-08-26-EXTERNAL-5.8.28-PACK.md`](AUDIT-2026-08-26-EXTERNAL-5.8.28-PACK.md);
55
- the two pack fixes are included in release 5.9.7, with release-artifact verification
55
+ the two pack fixes are included in release 5.9.8, with release-artifact verification
56
56
  remaining for detached execution and pack evidence.
57
57
 
58
- ### Reliability contracts in 5.9.7
58
+ ### Reliability contracts in 5.9.8
59
59
 
60
60
  Invalid analysis inputs fail before expensive work and use the structured
61
61
  `INVALID_INPUT` envelope: a missing `--consumer` repository, a malformed CVE
@@ -236,7 +236,7 @@ pipx install sourcecode # isolated install, no venv needed
236
236
 
237
237
  # Verify
238
238
  ask version
239
- # ask 5.9.7
239
+ # ask 5.9.8
240
240
  ```
241
241
 
242
242
  Requires Python 3.9+.
@@ -1381,6 +1381,10 @@ explaining. The rest do one thing; `ask <command> --help` is the whole story.
1381
1381
  | `ask chunk-file <file>` | supported | Split a large Java file into semantic chunks an agent can consume |
1382
1382
  | `ask intent "<question>"` | supported | Resolve a plain-language question to the typed `retrieve` query that answers it (scored lexical match against a declared vocabulary — no model, no generation). Prints the query; `--run` executes it. A question fitting two intents too closely is refused with both named. |
1383
1383
  | `ask rename-class` | supported | Word-boundary Java rename across the repository |
1384
+
1385
+ **Migration note:** `rename-class` requires the explicit `--from OldName --to NewName`
1386
+ options. Older positional name syntax is no longer accepted. Add `--dry-run` when
1387
+ updating an existing script so the planned file changes can be reviewed first.
1384
1388
  | `ask schema <name>` | supported | Print a published JSON Schema for this tool's output |
1385
1389
  | `ask self-audit` | supported | Check the SHIPPED build's own coherence — cache model, format contract, schema registry and output affordances. Declares explicitly that the semantic engine does not apply to this product's own source (ASK analyses Java; this build is Python), rather than reporting zeros. `ask selftest` is the different question: the defect ledger run against a real repository. |
1386
1390
  | `ask auth workspace <repo>...` | supported | Aggregate workspace entitlement preview. `--enforce` opts into the named-buyer pilot that reuses the existing Pro gate when the organization-sized threshold is crossed; advisory mode remains the default and the CLI does not bill. |
sourcecode/cli.py CHANGED
@@ -900,8 +900,8 @@ scope matches; `ask cache model` says exactly what a warm buys per command.
900
900
  [bold]Change and risk:[/bold]
901
901
  impact-chain <Class> . [dim]# blast radius; TX/SEC findings opt-in[/dim]
902
902
  impact <Class> . [dim]# reverse deps → endpoints reached[/dim]
903
- pr-impact . --files - [dim]# same, scoped to a diff on stdin; gating codes[/dim]
904
- pr-risk . --files - [dim]# one verdict for THIS diff; UNKNOWN fails the gate[/dim]
903
+ pr-impact . --files - [dim]# changed-file list on stdin; gating codes[/dim]
904
+ pr-risk . --files - [dim]# changed-file list on stdin; UNKNOWN fails the gate[/dim]
905
905
  posture . --since main [dim]# did this branch open an endpoint? (exp.)[/dim]
906
906
  drift . --profile prod [dim]# what opened up since the last capture[/dim]
907
907
  audit-report . --format markdown [dim]# signed human evidence bundle (exp.)[/dim]
@@ -1299,6 +1299,15 @@ def _preprocess_args(args: list[str]) -> list[str]:
1299
1299
  # got wrong instead of swallowing it and erroring on the next one.
1300
1300
  if _has_trailing_nonsubcommand_positional(result, i):
1301
1301
  _reject_unknown_command(arg)
1302
+ # A single missing token that is very close to a command is a command
1303
+ # typo, not a repository path. Existing directories retain the implicit
1304
+ # `ask <path>` grammar, including names that resemble commands.
1305
+ if not Path(arg).exists():
1306
+ _command_matches = difflib.get_close_matches(
1307
+ arg, sorted(_SUBCOMMANDS), n=3, cutoff=0.6
1308
+ )
1309
+ if _command_matches:
1310
+ _reject_unknown_command(arg)
1302
1311
  _set_detected_path(arg)
1303
1312
  _path_index = i
1304
1313
  if _path_index >= 0:
@@ -1455,6 +1464,56 @@ def _inject_cache_meta(raw: str, meta: dict) -> str:
1455
1464
  return raw
1456
1465
 
1457
1466
 
1467
+ def _inject_cache_meta_yaml(raw: str, meta: dict) -> str:
1468
+ """Inject the same cache provenance into a YAML answer as into JSON."""
1469
+ try:
1470
+ from io import StringIO
1471
+ from ruamel.yaml import YAML as _YAML
1472
+
1473
+ yaml = _YAML()
1474
+ obj = yaml.load(raw)
1475
+ if isinstance(obj, dict):
1476
+ obj["_cache"] = meta
1477
+ if "cache_source" in meta:
1478
+ obj["cache_source"] = meta["cache_source"]
1479
+ out = StringIO()
1480
+ yaml.dump(obj, out)
1481
+ return out.getvalue()
1482
+ except Exception:
1483
+ pass
1484
+ return raw
1485
+
1486
+
1487
+ def _refresh_delivery_timing_yaml(raw: str, *, served_from_cache: bool, elapsed_ms: float) -> str:
1488
+ """Refresh cache timing in YAML without routing the machine answer through JSON."""
1489
+ try:
1490
+ from io import StringIO
1491
+ from ruamel.yaml import YAML as _YAML
1492
+
1493
+ yaml = _YAML()
1494
+ obj = yaml.load(raw)
1495
+ if not isinstance(obj, dict):
1496
+ return raw
1497
+ meta = obj.setdefault("_meta", {})
1498
+ if not isinstance(meta, dict):
1499
+ return raw
1500
+ timing = meta.setdefault("timing_ms", {})
1501
+ if not isinstance(timing, dict):
1502
+ timing = {}
1503
+ meta["timing_ms"] = timing
1504
+ timing["total_ms"] = round(elapsed_ms, 2)
1505
+ timing["served_from_cache"] = served_from_cache
1506
+ timing["timing_basis"] = "served_from_snapshot" if served_from_cache else "computed"
1507
+ if served_from_cache:
1508
+ timing["phase_timing_basis"] = "snapshot_build"
1509
+ out = StringIO()
1510
+ yaml.dump(obj, out)
1511
+ return out.getvalue()
1512
+ except Exception:
1513
+ pass
1514
+ return raw
1515
+
1516
+
1458
1517
  def _refresh_delivery_timing(
1459
1518
  raw: str,
1460
1519
  *,
@@ -3557,7 +3616,17 @@ def _resolve_files_option(
3557
3616
  ),
3558
3617
  )
3559
3618
  raise typer.Exit(code=1)
3560
- return _text_input.parse_path_lines(_text_input.read_stdin_text()), "stdin"
3619
+ stdin_text = _text_input.read_stdin_text()
3620
+ if "diff --git " in stdin_text or "\n@@ " in stdin_text:
3621
+ _emit_error_json(
3622
+ INVALID_INPUT_CODE,
3623
+ "--files - expects a list of changed paths, not a raw unified diff.",
3624
+ hint=f"Pipe paths with: git diff --name-only REF | ask {command} . --files -",
3625
+ expected="One repository-relative file path per line.",
3626
+ reason="raw_diff_on_stdin",
3627
+ )
3628
+ raise typer.Exit(code=1)
3629
+ return _text_input.parse_path_lines(stdin_text), "stdin"
3561
3630
  as_path = Path(raw)
3562
3631
  if as_path.is_file():
3563
3632
  return (
@@ -3587,6 +3656,20 @@ def _resolve_files_option(
3587
3656
  def _git_changed_files(root: Path, since: Optional[str]) -> "tuple[list[str], str]":
3588
3657
  """Resolve a local Git diff without network access or repository mutation."""
3589
3658
  if since:
3659
+ # Resolve the ref through the shared authority before asking Git for the
3660
+ # diff, so every consumer publishes the canonical ref error code.
3661
+ from sourcecode.git_checkout import RefError, resolve_ref
3662
+
3663
+ try:
3664
+ resolve_ref(root, since)
3665
+ except RefError as exc:
3666
+ _emit_error_json(
3667
+ exc.code,
3668
+ exc.message,
3669
+ hint="Check the repository and ref, or pass --files explicitly.",
3670
+ ref=since,
3671
+ )
3672
+ raise typer.Exit(code=1)
3590
3673
  command = ["git", "diff", "--name-only", since, "HEAD"]
3591
3674
  description = f"git diff {since} HEAD"
3592
3675
  else:
@@ -6054,6 +6137,26 @@ def main(
6054
6137
  )
6055
6138
  except Exception:
6056
6139
  pass # stale value better than crash
6140
+ else:
6141
+ _cache_hit_content = _inject_cache_meta_yaml(
6142
+ _cache_hit_content,
6143
+ _cache_meta_block(
6144
+ cache_source=_hit_source,
6145
+ git_head_at_generation=_git_sha,
6146
+ current_git_head=_git_sha,
6147
+ has_uncommitted_changes=False,
6148
+ has_uncommitted_changes_basis="YAML cache delivery",
6149
+ generated_at=None,
6150
+ data_scope=("COMPACT" if compact else ("AGENT" if agent else "FULL")),
6151
+ target=target,
6152
+ with_ris_fact=True,
6153
+ ),
6154
+ )
6155
+ _cache_hit_content = _refresh_delivery_timing_yaml(
6156
+ _cache_hit_content,
6157
+ served_from_cache=True,
6158
+ elapsed_ms=(time.monotonic() - _t0) * 1000,
6159
+ )
6057
6160
  # C1: token economy on the agent-facing views (cache-hit path).
6058
6161
  if format == "json" and (compact or agent):
6059
6162
  from sourcecode.token_estimate import inject_token_economy as _inj_te
@@ -7828,31 +7931,33 @@ def prepare_context_cmd(
7828
7931
  # review-pr specific fields
7829
7932
  if task == "review-pr":
7830
7933
  if output.error_code:
7831
- _err_out: dict[str, Any] = {
7832
- "task": output.task,
7833
- "ci_decision": output.ci_decision or "error",
7834
- "error": output.error_code,
7835
- "message": output.error_message,
7836
- }
7837
- if output.since:
7838
- _err_out["since"] = output.since
7839
- if output.error_hints:
7840
- _err_out["hint"] = output.error_hints
7841
- # AUD-598-B01: an early return is still this run's whole answer, so
7842
- # it carries the same identity as the long one.
7843
- _err_json = _stamp_envelope(
7844
- json.dumps(_err_out, indent=2, ensure_ascii=_json_ensure_ascii())
7934
+ if output.error_code == "no_diff":
7935
+ _no_diff_out = {
7936
+ "task": output.task,
7937
+ "ci_decision": "no_changes",
7938
+ "summary": "No changes detected",
7939
+ }
7940
+ _no_diff_json = _stamp_envelope(
7941
+ json.dumps(_no_diff_out, indent=2, ensure_ascii=_json_ensure_ascii())
7942
+ )
7943
+ if output_path is not None:
7944
+ _safe_write_file(output_path, _no_diff_json)
7945
+ else:
7946
+ sys.stdout.buffer.write(_no_diff_json.encode("utf-8"))
7947
+ sys.stdout.buffer.write(b"\n")
7948
+ sys.stdout.buffer.flush()
7949
+ raise typer.Exit()
7950
+ _error_hint = " ".join(str(h) for h in (output.error_hints or []))
7951
+ _emit_error_json(
7952
+ output.error_code,
7953
+ output.error_message or "review-pr could not complete.",
7954
+ command="review-pr",
7955
+ ci_decision=output.ci_decision or "error",
7956
+ since=output.since or None,
7957
+ hint=_error_hint or None,
7958
+ hints=output.error_hints or None,
7845
7959
  )
7846
- if output_path is not None:
7847
- _safe_write_file(output_path, _err_json)
7848
- else:
7849
- sys.stdout.buffer.write(_err_json.encode("utf-8"))
7850
- sys.stdout.buffer.write(b"\n")
7851
- sys.stdout.buffer.flush()
7852
- # FIX: no_diff (no PR changes) is not an error — exit 0, consistent
7853
- # with delta's no_changes handling. Only true errors exit non-zero.
7854
- _review_pr_exit = 0 if output.error_code == "no_diff" else 1
7855
- raise typer.Exit(code=_review_pr_exit)
7960
+ raise typer.Exit(code=1)
7856
7961
  out["review_type"] = "pull_request"
7857
7962
  if output.ci_decision:
7858
7963
  out["ci_decision"] = output.ci_decision
@@ -15675,6 +15780,7 @@ def impact_chain_cmd(
15675
15780
  f"{evt_result.metadata.get('consumer_count', 0)} consumers)"
15676
15781
  ),
15677
15782
  )
15783
+ _exit_on_unresolved_target(evt_result.resolution)
15678
15784
  return
15679
15785
 
15680
15786
  result = run_impact_chain(
@@ -16051,6 +16157,15 @@ def explain_cmd(
16051
16157
  else:
16052
16158
  output = explanation.render_text()
16053
16159
 
16160
+ if not explanation.found:
16161
+ _emit_error_json(
16162
+ INVALID_INPUT_CODE,
16163
+ f"Class '{class_name}' was not found in repository symbols.",
16164
+ hint="Pass an existing class name or FQN; use `ask repo-ir` for the symbol list.",
16165
+ expected="A class present in the analyzed repository.",
16166
+ )
16167
+ raise typer.Exit(code=1)
16168
+
16054
16169
  _emit_command_output(output, output_path, copy,
16055
16170
  success_msg=f"Explanation written to {output_path}")
16056
16171
 
@@ -18059,6 +18174,10 @@ def selftest_cmd(
18059
18174
  "checkout's runner). Published with every verdict — the difference "
18060
18175
  "ASK-09 hid in was the entry point, not the repository.",
18061
18176
  ),
18177
+ timeout: int = typer.Option(
18178
+ 120, "--timeout", min=1,
18179
+ help="Maximum seconds allowed for each ledger row (default: 120).",
18180
+ ),
18062
18181
  output_path: Optional[Path] = typer.Option(
18063
18182
  None, "--output", "-o", help="Write the verdicts to a file instead of stdout.",
18064
18183
  ),
@@ -18111,7 +18230,9 @@ def selftest_cmd(
18111
18230
  _prog = Progress()
18112
18231
  _prog.start("running the ledger against this repository")
18113
18232
  try:
18114
- data = run_selftest(target, rows=selected, entry_point=entry_point)
18233
+ data = run_selftest(
18234
+ target, rows=selected, entry_point=entry_point, timeout=timeout
18235
+ )
18115
18236
  finally:
18116
18237
  _prog.stop()
18117
18238
 
@@ -19413,7 +19534,7 @@ def cold_start_cmd(
19413
19534
  _notice(
19414
19535
  f"WARNING: Output is ~{_tokens // 1000}K tokens. This exceeds the context window of "
19415
19536
  "most LLMs (GPT-4o: 128K, Claude Sonnet: 200K). "
19416
- "Use --compact for a ~10K token subset, or --output FILE to save."
19537
+ "Use --compact for a snapshot-dependent orientation subset, or --output FILE to save."
19417
19538
  )
19418
19539
  # AUD-596-D01: this payload builds its own `_meta` above (estimated tokens,
19419
19540
  # token economy) and used to skip the envelope for that reason — so the one
sourcecode/license.py CHANGED
@@ -715,8 +715,8 @@ def require_pro(feature_name: str) -> None:
715
715
  def activate_license(license_key: str) -> None:
716
716
  """Validate license_key via Edge Function, write ~/.sourcecode/license.json.
717
717
 
718
- Outputs JSON to stdout; exits 0 on success, 1 on any failure.
719
- Never raises — all error paths emit JSON and call sys.exit(1).
718
+ Outputs JSON to stdout on success; exits 0 on success, 1 on any failure.
719
+ Errors use the CLI JSON envelope on stderr so stdout remains machine-safe.
720
720
  """
721
721
  if not _LICENSE_KEY_RE.match(license_key):
722
722
  _fail("invalid_license", "License key format is invalid.")
@@ -760,8 +760,10 @@ def activate_license(license_key: str) -> None:
760
760
  # ---------------------------------------------------------------------------
761
761
 
762
762
  def _fail(error: str, message: str) -> None:
763
- """Emit JSON error to stdout and exit 1. Never returns."""
764
- payload = {"error": error, "message": message}
765
- sys.stdout.write(json.dumps(payload, ensure_ascii=False) + "\n")
766
- sys.stdout.flush()
763
+ """Emit the shared structured error envelope to stderr and exit 1."""
764
+ from sourcecode.error_schema import build_error_envelope
765
+
766
+ payload = build_error_envelope(error, message, command="activate")
767
+ sys.stderr.write(json.dumps(payload, ensure_ascii=False) + "\n")
768
+ sys.stderr.flush()
767
769
  sys.exit(1)
sourcecode/packs.py CHANGED
@@ -22,6 +22,7 @@ import json
22
22
  import subprocess
23
23
  import sys
24
24
  import tempfile
25
+ import threading
25
26
  import time
26
27
  from pathlib import Path
27
28
  from typing import Any, Callable, Optional, Sequence
@@ -681,9 +682,29 @@ def _run_command(command: str, root: Path, output: Path, extra: list[str]) -> di
681
682
  # Run from the repository so relative deployment inputs and build-tool
682
683
  # discovery have the same meaning as they do for a user invoking ASK there.
683
684
  started = time.monotonic()
684
- completed = subprocess.run(
685
- argv, capture_output=True, text=True, check=False, cwd=str(root),
685
+ process = subprocess.Popen(
686
+ argv,
687
+ stdout=subprocess.PIPE,
688
+ stderr=subprocess.PIPE,
689
+ text=True,
690
+ cwd=str(root),
686
691
  )
692
+ stderr_lines: list[str] = []
693
+
694
+ def _forward_stderr() -> None:
695
+ assert process.stderr is not None
696
+ for line in process.stderr:
697
+ stderr_lines.append(line)
698
+ # Child diagnostics are operational progress/errors, never pack data.
699
+ sys.stderr.write(line)
700
+ sys.stderr.flush()
701
+
702
+ stderr_thread = threading.Thread(target=_forward_stderr, daemon=True)
703
+ stderr_thread.start()
704
+ assert process.stdout is not None
705
+ stdout_text = process.stdout.read()
706
+ process.wait()
707
+ stderr_thread.join(timeout=1)
687
708
  duration_ms = int((time.monotonic() - started) * 1000)
688
709
  payload: Any = None
689
710
  if output.is_file():
@@ -694,9 +715,9 @@ def _run_command(command: str, root: Path, output: Path, extra: list[str]) -> di
694
715
  return {
695
716
  "command": command,
696
717
  "invocation": ["ask", command, *extra, str(root), "--format", "json"],
697
- "exit_code": completed.returncode,
718
+ "exit_code": process.returncode,
698
719
  "payload": payload,
699
- "stderr": completed.stderr[-4000:] if completed.stderr else None,
720
+ "stderr": "".join(stderr_lines)[-4000:] if stderr_lines else None,
700
721
  # AUD-600-D02: the clock the manifest was missing, taken where the
701
722
  # component actually runs.
702
723
  "duration_ms": duration_ms,
sourcecode/progress.py CHANGED
@@ -523,13 +523,15 @@ class Progress:
523
523
 
524
524
  def _slow_warning_loop(self) -> None:
525
525
  """Give non-interactive supervisors a delayed liveness signal only."""
526
- if self._stop_event.wait(timeout=self._slow_warning_after) or self._stopped:
527
- return
528
- try:
529
- self._write(
530
- f"[ask] warning: run has exceeded {_duration(self._slow_warning_after)}; "
531
- "still working (set --progress stderr for periodic heartbeats)\n"
532
- )
533
- self._slow_warning_emitted = True
534
- except Exception:
535
- pass
526
+ while not self._stop_event.wait(timeout=self._slow_warning_after):
527
+ if self._stopped:
528
+ return
529
+ try:
530
+ elapsed = time.monotonic() - self._t0
531
+ self._write(
532
+ f"[ask] warning: run has exceeded {_duration(elapsed)}; "
533
+ "still working (set --progress stderr for periodic heartbeats)\n"
534
+ )
535
+ self._slow_warning_emitted = True
536
+ except Exception:
537
+ pass
sourcecode/selftest.py CHANGED
@@ -872,6 +872,7 @@ def run_selftest(
872
872
  *,
873
873
  rows: "tuple[str, ...]" = (),
874
874
  entry_point: "str | None" = None,
875
+ timeout: int = 120,
875
876
  ) -> "dict[str, Any]":
876
877
  """Run the ledger's assertions against *repo* and publish the verdicts."""
877
878
  from sourcecode.repository_ir import find_java_files
@@ -881,6 +882,7 @@ def run_selftest(
881
882
  entry_point=entry_point or _entry_point(),
882
883
  platform=f"{_platform_label()} / python "
883
884
  f"{_platform.python_version()}",
885
+ timeout=timeout,
884
886
  )
885
887
  try:
886
888
  subject.java_files = len(find_java_files(Path(repo)))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.9.7
3
+ Version: 5.9.8
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  Project-URL: Homepage, https://github.com/HarounDominique/sourcecode
6
6
  Project-URL: Repository, https://github.com/HarounDominique/sourcecode
@@ -59,7 +59,7 @@ Description-Content-Type: text/markdown
59
59
  > question. All analysis is local and deterministic; see [Privacy](#configuration--privacy)
60
60
  > before inspecting a repository whose telemetry policy you need to control.
61
61
 
62
- ![Version](https://img.shields.io/badge/version-5.9.7-blue)
62
+ ![Version](https://img.shields.io/badge/version-5.9.8-blue)
63
63
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
64
64
 
65
65
  Copyright (c) 2026 Dominique Haroun. All rights reserved. ASK Engine 5.7.0 and
@@ -196,7 +196,7 @@ set `ASK_MAX_RSS_MB=<megabytes>`; if the process exceeds it, ASK refuses the
196
196
  answer with `MEMORY_TOO_LARGE`, including the observed peak and limit. Leave it
197
197
  unset, or set it to `0`, to disable the ceiling explicitly.
198
198
 
199
- **Current performance status.** Release 5.9.7 retains the shared Canonical IR
199
+ **Current performance status.** Release 5.9.8 retains the shared Canonical IR
200
200
  path used by `validation` and now passes that same CIR into labelled `data-exposure`
201
201
  runs; the no-label path remains parse-free. These are implementation properties,
202
202
  not duration promises. A controlled external warm-path audit has opened performance
@@ -218,7 +218,7 @@ in `overlapping_paths`; a missing or non-directory path is rejected as structure
218
218
  invalid input rather than treated as an empty repository. This prevents silent
219
219
  entitlement errors in CI and does not change per-repository gates or billing.
220
220
 
221
- Release 5.9.7 also hardens the boundary contracts: missing consumer repositories,
221
+ Release 5.9.8 also hardens the boundary contracts: missing consumer repositories,
222
222
  malformed CVE feeds and unresolved `pack gate --since` refs fail as structured
223
223
  input errors; duplicate same-commit baselines are never overwritten. `posture
224
224
  --diff` validates unknown profiles when the repository declares profiles. In
@@ -251,7 +251,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
251
251
  # pip / pipx
252
252
  pipx install sourcecode # or: pip install sourcecode
253
253
 
254
- ask version # ask 5.9.7 — and, on a build that has aged,
254
+ ask version # ask 5.9.8 — and, on a build that has aged,
255
255
  # how many releases have probably shipped since
256
256
  ```
257
257
 
@@ -501,6 +501,10 @@ The everyday loop: diff-based PR review, symptom-driven bug triage, and delta co
501
501
 
502
502
  ### 7 · Utilities
503
503
  `ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / model / clear / freshness) · `ask self-audit` (does the installed build's own registry agree with itself?)
504
+
505
+ `rename-class` migration note: current releases require the explicit form
506
+ `ask rename-class <repo> --from OldName --to NewName`. Older positional forms are
507
+ not accepted; use `--dry-run` first when migrating scripts.
504
508
  → [reference](docs/USER_GUIDE.md)
505
509
 
506
510
  ---
@@ -1,6 +1,6 @@
1
- sourcecode/__init__.py,sha256=gFKYhRgFEIRJQkCoClBu-R4CIT4KIDVnPAvdp9RZjgA,308
1
+ sourcecode/__init__.py,sha256=VaWEpHF7AmkJDgZPh7icZZV57BxpC4dhyJ60KSvRMGk,308
2
2
  sourcecode/__main__.py,sha256=qDFVkobwsdZrX0B3stiRqsUNivVpybKO-egzAwCW4xw,165
3
- sourcecode/_build_commit.py,sha256=7TTq7KpgqFZyS9X9WdPvNJ9CJ5-afbJ6tFk_zAiwjzM,9290
3
+ sourcecode/_build_commit.py,sha256=5AagM-XxyCpXU4voHWE61m8PiJyu8NusU-e7n9q3ZFc,9899
4
4
  sourcecode/access_drift.py,sha256=1R7_fiAPvKNOnxc9uxkH3JH-k8MiAuyE7FwWUX1r4Fg,8995
5
5
  sourcecode/adaptive_scanner.py,sha256=yJBKjNpkY6bpueYJ2YnRezen3sYZDecEt7WaaNWdqug,9466
6
6
  sourcecode/analysis_budget.py,sha256=ZuNEboPF8A6GK-_V7WNt92ezgriga7_Rbr-vvSN4UEE,4183
@@ -35,7 +35,7 @@ sourcecode/change_plan.py,sha256=drAoDsqFplutCLc6Y0xue7sYkTls0SpYh7aOXvttv3I,129
35
35
  sourcecode/ci_output.py,sha256=X4NRokWWMRF9Ex8OQrEO2g04GzJ00GDP5zYIoqI9YCc,4625
36
36
  sourcecode/cir_graphs.py,sha256=RytqSv1WF8kdlfXj2fPQz16LY4akS2kyThbdWL8beCQ,14835
37
37
  sourcecode/classifier.py,sha256=JBzPwSSrDG-tUHAbcKB678HRbjLpD-ohzbzzO62mgpo,20114
38
- sourcecode/cli.py,sha256=ULjbDXHGezsDnbdW2be3oci6LuXvHDNUwEmDMtyNL7M,938155
38
+ sourcecode/cli.py,sha256=1WvEmGQjDGsYDCq4eMm7JM4opKHZjagoVvCKqCUdw6s,942911
39
39
  sourcecode/client_calls.py,sha256=YOPnfRZzRyqmdHvXSVeiunW8cuiuCuWXacNIQRgKMCw,22640
40
40
  sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
41
41
  sourcecode/compare.py,sha256=Lnfmm9I3k0H1jP1tV6ZJ-R7znjQPLPLCe5TzV1Jb_PM,15323
@@ -96,7 +96,7 @@ sourcecode/identity_fallback.py,sha256=uRC_j_80uaI4Ue4tf-OhKX4h472dmufYcjEFGSxY2
96
96
  sourcecode/integration_coordinates.py,sha256=rvuApnS7WdRUbeQLg_oKj-Gi0koO2RKdw6HenXNgrDo,12443
97
97
  sourcecode/intent_router.py,sha256=hC_o0VYfSjzSXecFkpiD7vzFgvt44YAw6E_jrMeGiZ4,15555
98
98
  sourcecode/jdk_exports.py,sha256=fCrlwNAXUT9gge_joq6kMnY3zJxYB2pxqy-0w3o3MJI,874
99
- sourcecode/license.py,sha256=Rx_TXEztUJB9TzI352hEh8cmCd-30J9WS6iT4EndcW0,30974
99
+ sourcecode/license.py,sha256=eIEuIVQXywl_S9LOIACOEpJ4M5RyaPvWrqg_jSNOrXA,31088
100
100
  sourcecode/manifest_cache.py,sha256=aPRHUs781d00fVbtlTiSaq0-AS9bAqS7_zJ0snZvlJs,2244
101
101
  sourcecode/mcp_nudge.py,sha256=beNjfyb7z09T1rnS4t6Q4qfbLzZQNaP6ddCA4XpmV0s,3256
102
102
  sourcecode/metrics_analyzer.py,sha256=gLoRWKygF18jLgwsqmGXSWopw-f5iO1VbM7Jjdif6ag,22809
@@ -112,7 +112,7 @@ sourcecode/output_ceiling.py,sha256=rMLDHbXeC6C_uP8iQSVbbCGiJ_n0gMr2YI9zt5nltFA,
112
112
  sourcecode/output_encoding.py,sha256=OxiZQtr7uWBDUtblNQviNHsTH1Xo9AZEpsegPlQWKFk,2139
113
113
  sourcecode/output_sink.py,sha256=Eya-PnXxqc3RGulJoLhuC9LUF73SZD0aO5O2B0xAMXU,8762
114
114
  sourcecode/pack_manifest.py,sha256=Qm6et6SQsFCLc-HJ-Uhz1XlcOa77ZDHgks4JVDEENss,20820
115
- sourcecode/packs.py,sha256=y5IGuzF4LYzZl9z5WtkxjWFAmUNphDvmbHUFGkuUieE,48879
115
+ sourcecode/packs.py,sha256=_f3bRzGIy_Cv2cSUMSco3e6nKxJbApT47PUYMEZwZEw,49506
116
116
  sourcecode/parallel.py,sha256=QocwdZoUabdxzd_jEz7f6B2XMsYWFaCFaIl0tIEQs3g,10546
117
117
  sourcecode/parse_cache.py,sha256=BaPzh-KygmY4OpJQm2YGh6PWztYsj58vHWTu2eSF4s8,38769
118
118
  sourcecode/partial_contract.py,sha256=FZUBACkClvRAmPeYVjxNWeQmP6Y22KW4fPeeTfmT80A,5951
@@ -128,7 +128,7 @@ sourcecode/pr_impact.py,sha256=8RgTJgvEThezh-Vm65eiFvJBdb45VjcbewEk5P144-0,39184
128
128
  sourcecode/pr_risk.py,sha256=Qbj1aK-JsdTQd_nji_-RaZAL3WUbwqDg9aH-cHQkoog,11354
129
129
  sourcecode/prepare_context.py,sha256=QsJiKoJRNn5_1adyBbKguH_wiaM8hpPLE0fLG9J4ilU,245016
130
130
  sourcecode/product_info.py,sha256=rpuCDf0KM2SD-WP8vw2tjdcbhWPsOGEVjSWqS8fkzlo,4966
131
- sourcecode/progress.py,sha256=frGEzCq-6gIQzPocrLyeEVLIzLmSnDauoX-3H6yE-3I,23054
131
+ sourcecode/progress.py,sha256=3tO-rKlRpPPFnRU-qIlQMyq4lsiecMo4GqxEsxAnpMA,23147
132
132
  sourcecode/provenance.py,sha256=gLbsLv0gze7k7ChM4i5M3MwKfFPzs8wzM72rUd2C5sM,7342
133
133
  sourcecode/ranking_engine.py,sha256=ZAucq_YX2KkWUuAZf4P0lhtQ_38vEFnUhuGtSZd1S0E,12970
134
134
  sourcecode/readiness_timeline.py,sha256=KjghC1MWH7Tzto97TBR3N0F8FkR87w5z7lZ1QsWvAQE,8506
@@ -167,7 +167,7 @@ sourcecode/security_config_scan.py,sha256=LU8gfNUBB6wjKR8jkK-qRKtUrbkHZ301_Xsk6h
167
167
  sourcecode/security_posture.py,sha256=ZWgWMsVdvkDHOkTtAy6T3Q9Kp8ufWsdqPsFQZVBNAFM,56885
168
168
  sourcecode/selection_contract.py,sha256=O3q_zHBgUsp1SDukqmH9nOUO6HxLFH_7fAqVL7JMV_A,1974
169
169
  sourcecode/self_audit.py,sha256=ZK6VZwbkTL66f4Q4U_JD6sdl6KjQ4DvtPcn5XqGcZDY,11541
170
- sourcecode/selftest.py,sha256=WjD2xMa55k2svoBMpBLpHCPMip3rtSNUbskSqsuB3iY,40056
170
+ sourcecode/selftest.py,sha256=PpQhoXqU4DTPMTIZL7am_N-R9byCWF7Ye3i4QjH1k-I,40105
171
171
  sourcecode/semantic_analyzer.py,sha256=xGwQvhU9xeOlZ4N-TPXFZT8HBHx4Rg0nPwu8nDFl00Y,95621
172
172
  sourcecode/semantic_impact_engine.py,sha256=t09IirGC3JjQDy33JZd1_WKzQVKXkoNl3-XEUr5kjis,20563
173
173
  sourcecode/semantic_integration_engine.py,sha256=ZjyKJKOj-adScWlYBuWx8Ee_P0F4_OImUJVnCYgopuU,20952
@@ -273,13 +273,13 @@ sourcecode/telemetry/consent.py,sha256=-Wb8BFGXEexOs8M0Eja7F-T6ZtLNPeRoZnHcHvlP7
273
273
  sourcecode/telemetry/events.py,sha256=l3Z2SQUO4_C2D2ItXOOdVNimAmHedUHnUxqYFTxnsAE,2900
274
274
  sourcecode/telemetry/filters.py,sha256=-lqT2oorECuqEIdeHb--7AZ6BCaUx0bya720a-Z5x6w,7335
275
275
  sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
276
- sourcecode/_docs/DEFECT-LEDGER.md,sha256=ln-d2Sw8RWXfqWZoJLGmBl3AceG4wPEDPpNhVQEdlgg,1123683
276
+ sourcecode/_docs/DEFECT-LEDGER.md,sha256=_ykq1oxsyb7OSPCiJ-9hP_NCqaKF5BGXCFwrjGLsJmw,1127987
277
277
  sourcecode/_docs/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
278
278
  sourcecode/_docs/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
279
- sourcecode/_docs/USER_GUIDE.md,sha256=K9kO1AzIBfwpM3U02sBPPQuyBIA6GU3UBBO0OojgpgI,104721
280
- sourcecode-5.9.7.dist-info/METADATA,sha256=rnWzcNS9xiYtpYSTsxzwRh4J7KuUGqsXWi9MPhgKmH8,64752
281
- sourcecode-5.9.7.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
282
- sourcecode-5.9.7.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
283
- sourcecode-5.9.7.dist-info/licenses/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
284
- sourcecode-5.9.7.dist-info/licenses/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
285
- sourcecode-5.9.7.dist-info/RECORD,,
279
+ sourcecode/_docs/USER_GUIDE.md,sha256=rphp6Vh3E9tPKwKeeqIgtuY5v_QPcnV-YO588GnmBCI,104970
280
+ sourcecode-5.9.8.dist-info/METADATA,sha256=ExptbMq0fys0kg8Jt196tJLfZQc8_VosmEN0j6o_bLM,64969
281
+ sourcecode-5.9.8.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
282
+ sourcecode-5.9.8.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
283
+ sourcecode-5.9.8.dist-info/licenses/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
284
+ sourcecode-5.9.8.dist-info/licenses/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
285
+ sourcecode-5.9.8.dist-info/RECORD,,