custody-describe apply: record HTTP code, merge-put fallback when patch is refused
Third founder run: every write exited 2 (bao's generic error code), cause not visible. The receipt now keeps only the HTTP status from stderr; on 403/405 for patch it reads metadata (never data), merges and writes it back whole, preserving custom_metadata set by earlier CCRs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 327203@bnt-lap001 Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
This commit is contained in:
parent
6c9b450043
commit
6bab3bbfdf
2 changed files with 66 additions and 25 deletions
|
|
@ -127,22 +127,45 @@ REAL_HOME = pwd.getpwuid(os.getuid()).pw_dir
|
|||
RECEIPT = os.path.join(REAL_HOME, ".local/state/railiance/receipts/custody-describe.json")
|
||||
|
||||
|
||||
def _bao(args: list[str], env: dict) -> tuple[int, str, str]:
|
||||
"""Run bao; return (rc, stdout, http_code). stderr is reduced to its HTTP code."""
|
||||
r = subprocess.run(["bao", *args], capture_output=True, text=True, env=env)
|
||||
m = re.search(r"Code: (\d{3})", r.stderr or "")
|
||||
return r.returncode, r.stdout, (m.group(1) if m else ("" if r.returncode == 0 else "no-code"))
|
||||
|
||||
|
||||
def _write(mount: str, rest: str, fields: dict, env: dict) -> str:
|
||||
flags = [f"-custom-metadata={k}={_clip(v)}" for k, v in fields.items()]
|
||||
rc, _, code = _bao(["kv", "metadata", "patch", f"-mount={mount}", *flags, rest], env)
|
||||
if rc == 0:
|
||||
return "patched"
|
||||
if code not in ("403", "405"):
|
||||
return f"failed patch http={code}"
|
||||
# No patch capability: read metadata (never data), merge, write it back whole,
|
||||
# so custom_metadata set by earlier CCRs survives.
|
||||
import json
|
||||
rc, out, code = _bao(["kv", "metadata", "get", "-format=json", f"-mount={mount}", rest], env)
|
||||
if rc != 0:
|
||||
return f"failed metadata-get http={code}"
|
||||
current = ((json.loads(out or "{}").get("data") or {}).get("custom_metadata")) or {}
|
||||
merged = {**current, **{k: _clip(v) for k, v in fields.items()}}
|
||||
flags = [f"-custom-metadata={k}={v}" for k, v in merged.items()]
|
||||
rc, _, code = _bao(["kv", "metadata", "put", f"-mount={mount}", *flags, rest], env)
|
||||
return "merged" if rc == 0 else f"failed put http={code}"
|
||||
|
||||
|
||||
def apply(doc: dict, receipt: str = RECEIPT) -> int:
|
||||
"""Silent: the warden wrapper refuses any output, so results go to a 0600 receipt."""
|
||||
import json
|
||||
env = dict(os.environ)
|
||||
env.setdefault("BAO_ADDR", "http://127.0.0.1:18200")
|
||||
results = {}
|
||||
for path, e in doc.items():
|
||||
if e.get("review") != "accepted" or any(not e.get(k) for k in REQUIRED):
|
||||
results[path] = "skipped"
|
||||
continue
|
||||
mount, rest = path.split("/", 1)
|
||||
args = ["bao", "kv", "metadata", "patch", f"-mount={mount}"]
|
||||
args += [f"-custom-metadata={k}={_clip(e[k])}" for k in REQUIRED]
|
||||
args.append(rest)
|
||||
env = dict(os.environ)
|
||||
env.setdefault("BAO_ADDR", "http://127.0.0.1:18200")
|
||||
rc = subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env).returncode
|
||||
results[path] = "patched" if rc == 0 else f"failed rc={rc}"
|
||||
results[path] = _write(mount, rest, {k: e[k] for k in REQUIRED}, env)
|
||||
os.makedirs(os.path.dirname(receipt), mode=0o700, exist_ok=True)
|
||||
old_umask = os.umask(0o077)
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue