Dashboard › institutional-transition-lab › Session 0sYM3EtB7rSN
0sYM3EtB7rSNFj77gPerform a fresh, read-only security review of ONLY the CLI output and failure-safety boundary for issue #4 in /home/byk/Code/institutional-transition-lab. This replaces a reviewer that returned empty twice and is disjoint from the immutable-input/archive reviewer. Do not edit files. Do not inspect or adjudicate governance source records, model codings, outcomes, transition dates, reports, detector output, or any active source-review scope.
Scope is strictly limited to:
Primary files: main/output helpers in src/institution_lab/governance_adjudication.py and CLI/output-focused tests in tests/test_governance_adjudication.py. Do not overlap the other reviewer’s manifest parser, input reader, hash, or ZIP internals except to treat their documented interfaces as callers.
Review the current working copy. Run narrow read-only tests/probes where useful. Look for race conditions, aliases, partial writes, stale-success artifacts, and paths that exit successfully after destructive or malformed behavior.
Return substantive evidence, never an empty result. Findings first, ordered by severity, each classified PASS, CONCERN, MUST-FIX, or BLOCKED with exact current file:line references. Every defect must include a deterministic regression. If no defect exists, state PASS explicitly and list the tests/probes you relied on plus residual risks. End the final line exactly MERGE or DO-NOT-MERGE. If tools prevent review, report BLOCKED first with the exact tool/error and end DO-NOT-MERGE.
Found 52 matches
/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py:
Line 97: descriptor = os.open(path, flags)
Line 100: with os.fdopen(descriptor, "rb") as source:
Line 201: with archive.open(info) as source:
Line 418: errors.append(f"{prefix}: resolved decision requires final_coding")
Line 425: if not isinstance(record.get("unresolved_reason"), str) or not record.get(
Line 426: "unresolved_reason"
Line 428: errors.append(f"{prefix}: abstain requires unresolved_reason")
Line 430: if decision != "abstain" and record.get("unresolved_reason") is not None:
Line 431: errors.append(f"{prefix}: resolved decision requires null unresolved_reason")
Line 437: errors.append(f"{prefix}: resolved decision cannot use abstain final class")
Line 443: errors.append(f"{prefix}: reject must resolve to a non-institutional class")
Line 496: errors.append(f"{prefix}: resolved decision requires ...
Found 37 matches
/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py:
Line 56: "summary_json": tmp_path / "summary.json",
Line 57: "summary_markdown": tmp_path / "summary.md",
Line 98: "summary_json",
Line 99: "summary_markdown",
Line 111: lambda *_args, **_kwargs: ([], {"canonicalization_gate": "open"}),
Line 312: def test_one_abstention_keeps_canonicalization_gate_closed() -> None:
Line 328: assert summary["canonicalization_gate"] == "closed"
Line 342: assert summary["canonicalization_gate"] == "closed"
Line 352: assert summary["canonicalization_gate"] == "closed"
Line 371: assert summary["canonicalization_gate"] == "closed"
Line 389: assert summary["canonicalization_gate"] == "closed"
Line 420: assert summary["canonicalization_gate"] == "closed"
Line 447: assert summary["canonicalization_gate"] == "closed"
Line 457: assert summary["canonicalization_gate"] == "closed"
Line 474: assert ...
<path>/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py</path>
<type>file</type>
<content>
760: _validate_record(
761: record,
762: documents_by_id[record_id],
763: coding_by_id[record_id],
764: reviewer_ids,
765: )
766: )
767: return errors
768:
769:
770: def validate_against_schema(adjudication: dict[str, Any], schema: dict[str, Any]) -> list[str]:
771: validator = Draft202012Validator(schema, format_checker=FormatChecker())
772: return [
773: f"schema {'.'.join(str(part) for part in error.absolute_path) or '<root>'}: "
774: f"{error.message}"
775: for error in sorted(validator.iter_errors(adjudication), key=lambda item: list(item.path))
776: ]
777:
778:
779: def render_markdown(adjudication: dict[str, Any], summary: dict[str, Any]) -> str:
780: lines = [
781: "# OSS governance adjudication v1",
782: "",
783: f"Canonicalization gate: **{summary['canonicalization_gate']}**",
784: "",
785: "## ...
<path>/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py</path> <type>file</type> <content> 1: from __future__ import annotations 2: 3: import copy 4: import json 5: import os 6: import subprocess 7: import sys 8: import zipfile 9: from pathlib import Path 10: 11: import pytest 12: 13: from institution_lab import governance_adjudication 14: from institution_lab.governance_adjudication import ( 15: DECISIONS, 16: FROZEN_INPUT_PINS, 17: REQUIRED_INPUT_PINS, 18: REVIEWER_ROLES, 19: REVIEWER_TYPES, 20: canonical_sha256, 21: file_sha256, 22: validate_adjudication, 23: validate_adjudication_fragment, 24: validate_against_schema, 25: verify_input_manifest, 26: ) 27: from institution_lab.governance_coding import ( 28: BODY_PATCH_RELATIONS, 29: CHANGE_STATUSES, 30: DIRECTIONS, 31: EVENT_KINDS, 32: RECORD_CLASSES, 33: RIGHT_KINDS, 34: ) 35: 36: ROOT = Path(__file__).parents[1] 37: MAX_TEST_ARCHIVE_MEMBERS = 256 38: 39: 40: def ...
<path>/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py</path>
<type>file</type>
<content>
750: "artifact_id": 9642983578,
751: "artifact_sha256": file_sha256(artifact),
752: "documents_sha256": "0" * 64,
753: "documents_file_sha256": file_sha256(documents),
754: "coding_package_file_sha256": file_sha256(coding_package),
755: "protocol_sha256": file_sha256(protocol),
756: "coding_schema_sha256": file_sha256(coding_schema),
757: "adjudication_schema_sha256": file_sha256(adjudication_schema),
758: }
759: monkeypatch.setattr(
760: "institution_lab.governance_adjudication.FROZEN_INPUT_PINS",
761: {k: manifest[k] for k in FROZEN_INPUT_PINS},
762: )
763: paths = {
764: "artifact": artifact,
765: "documents": documents,
766: "coding_package": coding_package,
767: "protocol": protocol,
768: "coding_schema": coding_schema,
769: "adjudication_schema": adjudication_schema,
770: }
771:
772: with pytest.raises(ValueError, ...
Found 10 matches
/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py:
Line 87: def _run_cli(monkeypatch: pytest.MonkeyPatch, paths: dict[str, Path]) -> None:
Line 776: def test_cli_validates_the_same_bytes_it_verifies(
Line 797: _run_cli(monkeypatch, paths)
Line 813: @pytest.mark.parametrize("alias_kind", ["direct", "symlink", "hardlink"])
Line 814: def test_cli_rejects_output_aliases_to_frozen_inputs(
Line 831: _run_cli(monkeypatch, paths)
Line 836: def test_cli_rejects_aliased_outputs(
Line 845: _run_cli(monkeypatch, paths)
Line 848: def test_cli_rejects_duplicate_manifest_keys(
Line 865: _run_cli(monkeypatch, paths)
/usr/bin/bash: line 1: pytest: command not found
/home/byk/Code/institutional-transition-lab/uv.lock /home/byk/Code/institutional-transition-lab/pyproject.toml
============================= test session starts ============================== platform linux -- Python 3.13.11, pytest-8.4.2, pluggy-1.6.0 rootdir: /home/byk/Code/institutional-transition-lab configfile: pyproject.toml plugins: anyio-4.14.2 collected 78 items / 51 deselected / 27 selected tests/test_governance_adjudication.py ........................... [100%] ====================== 27 passed, 51 deselected in 0.23s =======================
<path>/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py</path>
<type>file</type>
<content>
610: record.get("decision")
611: for record in adjudication_rows
612: if isinstance(record, dict) and record.get("decision") in DECISIONS
613: )
614: classes = Counter(
615: record["final_coding"]["record_class"]
616: for record in adjudication_rows
617: if isinstance(record, dict)
618: and isinstance(record.get("final_coding"), dict)
619: and isinstance(record["final_coding"].get("record_class"), str)
620: )
621: unresolved = [
622: record.get("record_id")
623: for record in adjudication_rows
624: if isinstance(record, dict) and record.get("decision") == "abstain"
625: ]
626: record_decisions = [
627: {
628: "record_id": record.get("record_id"),
629: "decision": record.get("decision"),
630: "final_class": (
631: record["final_coding"].get("record_class")
632: if isinstance(record.get("final_coding"), ...
{"body":"## Objective\n\nConduct a source-level, performance-blinded adjudication of every record in the frozen 40-record governance-coding corpus before any canonical power graph is created.\n\n## Frozen inputs\n\n- Governance coding protocol v1.2\n- Successful frozen artifact: Actions run `33063470968`, artifact `9642983578`\n- Exact 40-document bundle hash: `d70f7f795847968339a645b6dbd6d4428af6bd6044de44fa2602d4c4343b0ee9`\n- Treat run `33086454759` only as a stochastic repeat; do not replace the frozen v1.2 codings with it.\n\n## Method constraints\n\n- Keep repository performance outcomes and detected transition dates hidden.\n- Review the underlying source body/patch evidence, not only model summaries.\n- Record explicit `accept`, `revise`, `reject`, or `abstain` decisions.\n- Preserve evidence references and source URLs for every accepted fact.\n- Do not call the result “human adjudication” if an LLM performs any review; record reviewer type and assistance.\n- Gemini 3.7 Flash ...
No files found
No files found
{'input_clobbered_after_parent_swap': True}
{'exit_exception': 'forced second-output failure', 'json_gate': 'open', 'markdown_open': True}
{'masked_exception': 'forced failure-report write failure', 'json_gate': 'closed', 'markdown_open': True}
{'path_error': 'output paths alias each other', 'remaining_gate': 'open'}
{'json_gate': 'closed', 'markdown_closed_count': 1, 'markdown_open_count': 1, 'forged_heading_present': True}
{'json_gate_after_interrupt': 'open', 'markdown_open_after_interrupt': True}
{'symlink': 'output paths alias each other', 'hardlink': 'output paths alias each other'}
Found 1 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 115: "render_markdown",
{'destination_unchanged': True, 'temporary_files_remaining': []}
{'reraised_original': 'forced malformed input', 'json_gate': 'closed', 'markdown_closed': True, 'markdown_open': False}
?? src/institution_lab/governance_adjudication.py ?? tests/test_governance_adjudication.py
c686c4878409e68b958dd61850a59e9234416d817fc2fa3246fc728d51ebe0a5 src/institution_lab/governance_adjudication.py abf64b5e78a616d53b703dee5291ce7bf23fa9156fe59263a702e01cb8667bc5 tests/test_governance_adjudication.py
Found 2 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 934: result = subprocess.run( Line 950: assert result.returncode != 0
Found 35 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 120: def test_adjudication_schema_matches_validator_ontology() -> None: Line 142: def test_schema_enforces_uri_and_date_formats(field: str, value: str) -> None: Line 312: def test_one_abstention_keeps_canonicalization_gate_closed() -> None: Line 332: def test_record_ids_must_match_frozen_documents_exactly_once(mutation: str) -> None: Line 345: def test_accept_must_equal_the_named_frozen_response() -> None: Line 355: def test_resolved_decision_cannot_leave_final_coding_abstained() -> None: Line 382: def test_source_audit_must_match_complete_frozen_document(field: str, value: object) -> None: Line 406: def test_institutional_class_and_dates_must_agree( Line 423: def test_bounded_source_requires_explicit_evidence_limitation() -> None: Line 450: def test_accept_edge_revision_uses_the_accepted_response() -> None: Line 460: def ...
{'json_errors': ['forced schema error'], 'markdown_gate_closed': True, 'markdown_contains_error': False}
{'returncode': 1, 'stderr_has_alias_error': True, 'remaining_gate': 'open'}
{'returncode': 1, 'json_gate': 'closed', 'markdown_closed': True, 'markdown_open': False}
{'main_returned_success': True, 'input_replaced_by_open_summary': True}
{'main_returned_success': True, 'outputs_alias_after_swap': True, 'summary_json_is_valid_json': False}
c686c4878409e68b958dd61850a59e9234416d817fc2fa3246fc728d51ebe0a5 src/institution_lab/governance_adjudication.py abf64b5e78a616d53b703dee5291ce7bf23fa9156fe59263a702e01cb8667bc5 tests/test_governance_adjudication.py ?? src/institution_lab/governance_adjudication.py ?? tests/test_governance_adjudication.py
No files found
['fsync:file', 'replace']
MUST-FIX — Output-path TOCTOU can overwrite an input and still exit successfully.
Path identity is checked once at src/institution_lab/governance_adjudication.py:828-841 and :906. _atomic_write later resolves the mutable parent again for mkdir, mkstemp, and os.replace at :844-852.
A synthetic probe retargeted an output-parent symlink after validation. main() returned successfully and replaced --adjudication with an open summary. A second probe made both outputs alias; main() returned successfully while --summary-json contained Markdown rather than JSON.
Deterministic regression: Retarget a parent symlink during the first input callback. Assert nonzero exit, unchanged input bytes, distinct outputs, and valid closed summaries. Also retarget after temporary-file creation to test the rename boundary.
MUST-FIX — Failures before report writing preserve stale open summaries.
_validate_output_paths runs outside the protected block at :906-907, and the handler catches only Exception at :932. Nothing invalidates prior summaries before fallible work.
An actual subprocess with aliased outputs exited 1 but retained the prior JSON gate as open. A forced KeyboardInterrupt during the first read also left both prior open summaries unchanged. Existing alias tests at tests/test_governance_adjudication.py:813-845 check rejection and input preservation, but never check stale outputs.
Deterministic regression: Seed both outputs with open summaries, then parameterize path-validation failures, OSError, KeyboardInterrupt, and SystemExit. After every nonzero invocation, each output must be absent or unambiguously closed without modifying an aliased input.
MUST-FIX — The two summaries have no atomic publication or rollback.
Both normal output writes at :938-940 and failure writes at :878-879 occur sequentially. ...
Date: Sep 9, 2026 * 🔴 [requested-security-review] (03:03) User requested a fresh, read-only security review of only the CLI output and failure-safety boundary for issue #4 in `/home/byk/Code/institutional-transition-lab`, replacing a reviewer that returned empty twice and remaining disjoint from the immutable-input/archive reviewer. * 🔴 [enforced-review-scope] (03:03) User limited review scope …