NK-WP-0056-T04: reconcile tool reports a value-free error class

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 673304@bnt-lap001
Assistant-Session: 959b12c7-cf2e-440b-a60d-91229cc9e96e
This commit is contained in:
tegwick 2026-10-30 21:58:01 +01:00
parent a4b6a8f753
commit b19f7f6493
2 changed files with 16 additions and 3 deletions

View file

@ -74,9 +74,12 @@ def main():
report['custody_matches_live'] = bcrypt.checkpw(custody_value(root), hashed)
print(json.dumps(report, sort_keys=True))
return 0 if report['custody_matches_live'] or not apply else 1
except (Exception, KeyboardInterrupt):
except (Exception, KeyboardInterrupt) as error:
# Class and exit code only: messages and kubectl stderr may carry values.
detail = {'error': type(error).__name__}
if isinstance(error, subprocess.CalledProcessError): detail['exit_code'] = error.returncode
print(json.dumps({'result': 'unverified', 'phase': phase,
'partial_changes_possible': phase in ('write', 'readback')}), file=sys.stderr)
'partial_changes_possible': phase in ('write', 'readback'), **detail}), file=sys.stderr)
return 1

View file

@ -83,7 +83,8 @@ def test_refuses_when_live_pair_disagrees(case):
before = env.read_bytes()
result = run(case, '--apply')
assert result.returncode == 1 and result.stdout == ''
assert json.loads(result.stderr) == {'result': 'unverified', 'phase': 'live-pair', 'partial_changes_possible': False}
assert json.loads(result.stderr) == {'result': 'unverified', 'phase': 'live-pair', 'partial_changes_possible': False,
'error': 'Refused'}
assert env.read_bytes() == before
@ -93,3 +94,12 @@ def test_missing_custody_copy_is_reported_as_custody(case):
result = run(case)
assert result.returncode == 1
assert json.loads(result.stderr)['phase'] == 'custody'
def test_cluster_failure_reports_exit_code_only(case):
*_, environ, _ = case
(Path(environ['STATE']) / 'keycape-config').unlink()
result = run(case)
report = json.loads(result.stderr)
assert report['phase'] == 'cluster' and report['error'] == 'CalledProcessError' and report['exit_code'] == 1
assert LIVE not in result.stderr