You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
veche: add --json-out PATH, and say so on stderr when the gate skips the council (the twin is silently ignored) #2139
Scripts and agents that call veche.py have to read its result from stdout, which breaks in two ways.
The COUNCIL_BLOCKING_WORK alarm goes to stderr just before the record is printed (.claude/skills/idea-critic/scripts/veche.py:391-393), and so does the WARN packet is outside --root line (:182). The alarm fires on every COULD_NOT_DECIDE and on any council slower than --alarm-s (:389). In those runs a caller that redirects veche.py ... > result.json 2>&1 gets a file whose first line is not JSON, and json.load fails at character 0. We ended up writing a small extractor that scans a mixed log for the last {...} that contains a verdict.
The convene gate is silent (:205-208). With --stakes medium --reversibility easy --twin the script returns NOT_CONVENED (exit 4) in zero seconds, prints nothing on stderr, runs no seat, and ignores --twin (cost.calls is 0). The caller learns why only by reading reason in the record. --stakes and --reversibility have no help= text (:363-364); the rule that a call is skipped unless stakes are high or reversibility is hard appears only in references/council.md:11-14.
Minimal check for point 2:
python3 /path/to/perun/.claude/skills/idea-critic/scripts/veche.py --cmd false \
--claim c --steelman s --stakes medium --reversibility easy --twin > out.json
echo"exit $?"# 4, with nothing on stderr; out.json has "verdict": "NOT_CONVENED" and "calls": 0
Proposal
--json-out PATH: write the final record there (write a temporary file, then rename) on every outcome, including COULD_NOT_DECIDE and NOT_CONVENED. Stdout keeps printing it as today.
On NOT_CONVENED, print one stderr line, for example NOT_CONVENED: stakes=medium reversibility=easy; no seat ran, --twin ignored (declare --stakes high or --reversibility hard to convene).
Add help= to --stakes and --reversibility that states the gate rule.
Open question for the maintainers: should --twin still run alone on a skipped claim, since it is the cheapest way to get a dissent for a medium-stakes call?
Why not a different pack
This is about the output contract of Perun's own veche.py. The script already builds one JSON record, so the smallest step is to also write it to a file and to say out loud when it skipped the work.
Fixed across #2145 (release 1.622.0) and #2147 (release 1.623.0).
--json-out PATH writes the record on every outcome, including COULD_NOT_DECIDE and NOT_CONVENED, through a temp file in the same directory and os.replace, so a reader never sees half a record. Stdout still prints it.
A skipped council prints veche: NOT_CONVENED, no seat called (<reason>) on stderr, followed by ; --twin ignored when --twin was given.
--stakes and --reversibility have help text that states the gate: the council is skipped only when stakes are low or medium and reversibility is easy.
On the open question, behavior is unchanged: a skipped council runs no seat, including the twin, and the stderr line now says so.
Covered by scripts/test_veche_surface.py, scripts/test_veche_runtime.py, scripts/test_veche_json_out_exit_code.py and scripts/test_veche_json_out_late_write.py.
Activity
Wave 5: provisioned scanners with honest reporting, spend and pipelin…
Wave 6: decision-council surface fixes, standing every-test-wired che…
remigiusz-antczak commentedon Oct 30, 2026
Fixed across #2145 (release 1.622.0) and #2147 (release 1.623.0).
--json-out PATHwrites the record on every outcome, including COULD_NOT_DECIDE and NOT_CONVENED, through a temp file in the same directory andos.replace, so a reader never sees half a record. Stdout still prints it.veche: NOT_CONVENED, no seat called (<reason>)on stderr, followed by; --twin ignoredwhen--twinwas given.--stakesand--reversibilityhave help text that states the gate: the council is skipped only when stakes are low or medium and reversibility is easy.Covered by
scripts/test_veche_surface.py,scripts/test_veche_runtime.py,scripts/test_veche_json_out_exit_code.pyandscripts/test_veche_json_out_late_write.py.