From eb4f1010dd57781f399144f3e22b35d44f9bf6d3 Mon Sep 17 00:00:00 2001 From: chaoz23 Date: Sat, 22 Aug 2026 18:53:32 -0700 Subject: [PATCH] fix: accept --schema as a flag, per FAMILY.md clause 7 Clause 7 codifies `--schema` as a flag and binds it to every member class. table-kit had the capability only as a `schema` subcommand, so a fresh-context agent following the family contract verbatim issued `tablekit --schema` and was refused with exit 2. A differently-spelled surface does not discharge a clause that names the flag. main() special-cases only -h/--help/help and -V/--version before dispatching through COMMANDS, so any other leading --flag read as an unknown command. The alias normalises --schema to the existing subcommand; output is byte-identical and unknown flags are still rejected with exit 2. Also bumps the family-conformance job's srdcheck pin to 0fbc4b9d161a9ca7e378a73ad88421ff6b278af3, which is the first baseline that no longer waives SCHEMA_NOT_FLAG. Both changes must land together: the ratchet fails a waiver that no longer fires, so this repo fixed against the old pin would go red with STALE BASELINE. Verified both ways -- new baseline exit 0, old baseline exit 1 with the stale report. The three pre-existing srdcheck pins in this workflow are untouched; they serve different contract tests. Closes #23 Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 2 +- tablekit/cli.py | 6 ++++++ tests/test_contracts.py | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f37de7..1f2e48e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v5 with: repository: chaoz23/srdcheck - ref: 27dee98cb7cb86e6ef86e34568d08954179f9a82 + ref: 0fbc4b9d161a9ca7e378a73ad88421ff6b278af3 path: srdcheck-src - uses: actions/setup-python@v6 with: diff --git a/tablekit/cli.py b/tablekit/cli.py index 8d607c0..aa32f41 100644 --- a/tablekit/cli.py +++ b/tablekit/cli.py @@ -697,6 +697,12 @@ def main(argv=None): print(__version__) return 0 cmd = args.pop(0) + # FAMILY.md clause 7 codifies `--schema` as a flag, and it binds every member + # class. The capability already exists as a subcommand; accept the codified + # spelling as an alias so a fresh-context agent following the family contract + # verbatim is not refused. See chaoz23/table-kit#23. + if cmd == "--schema": + cmd = "schema" fn = COMMANDS.get(cmd) if not fn: print(f"unknown command {cmd!r}\n\n{USAGE}", file=sys.stderr) diff --git a/tests/test_contracts.py b/tests/test_contracts.py index 209bef5..23f2dc1 100644 --- a/tests/test_contracts.py +++ b/tests/test_contracts.py @@ -1,4 +1,5 @@ import copy +import io import json import os import subprocess @@ -140,6 +141,30 @@ def test_contract_cli_is_checkout_independent(self): self.assertEqual(json.loads(result.stdout)["properties"]["schema_version"]["const"], version) +class FamilyContractTests(unittest.TestCase): + """FAMILY.md clause 7 codifies `--schema` as a flag, and it binds every + member class. table-kit exposes the capability as a `schema` subcommand, so + the flag spelling is an alias -- without it a fresh-context agent following + the family contract verbatim is refused (chaoz23/table-kit#23).""" + + def _capture(self, argv): + buf = io.StringIO() + with redirect_stdout(buf): + code = main(argv) + return code, buf.getvalue() + + def test_schema_flag_is_accepted(self): + code, out = self._capture(["--schema"]) + self.assertEqual(code, 0) + json.loads(out) + + def test_schema_flag_matches_the_subcommand(self): + flag_code, flag_out = self._capture(["--schema"]) + cmd_code, cmd_out = self._capture(["schema"]) + self.assertEqual(flag_code, cmd_code) + self.assertEqual(json.loads(flag_out), json.loads(cmd_out)) + + class LegacyMigrationTests(unittest.TestCase): @classmethod def setUpClass(cls):