← Files note Workspace|ROGNALIAARCHIVED FILE
skills/note-draft/scripts/prepare_note_draft_registration.py
5.52 KB · Oct 2, 2026 · 00:33 UTC
#!/usr/bin/env python3
"""Create one immutable, approved registration package without browser actions."""
from __future__ import annotations
import argparse
import json
import sys
from typing import Any, Dict, Optional
from draft_common import (
DraftDataError,
build_registration_package,
build_registration_source,
draft_lock,
ensure_latest_article_revision,
ensure_store,
json_text,
load_all_registrations,
load_json_argument,
normalize_registration_input,
parse_timestamp,
read_events,
registration_payload_hash,
resolve_workspace,
validate_note_draft_data,
validate_approval_timing,
write_new_text,
)
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Save an approved note draft registration package locally."
)
parser.add_argument("workspace", help="Absolute path to the selected workspace")
parser.add_argument("--config", required=True, help="Registration JSON path, or -")
parser.add_argument("--timestamp", help="ISO 8601 timestamp override")
return parser
def _output(package: Dict[str, Any], status: str) -> Dict[str, Any]:
return {
"status": status,
"registration_status": package["status"],
"article_id": package["article_id"],
"article_revision": package["article_revision"],
"registration_revision": package["registration_revision"],
"registration_path": package["registration_path"],
"external_actions": [],
}
def main(argv: Optional[list[str]] = None) -> int:
args = _parser().parse_args(argv)
try:
workspace = resolve_workspace(args.workspace)
config = normalize_registration_input(
load_json_argument(args.config, "draft registration config")
)
created_at = parse_timestamp(args.timestamp)
with draft_lock(workspace, created_at):
errors, _ = validate_note_draft_data(workspace)
if errors:
raise DraftDataError(
"existing note draft data is invalid: " + "; ".join(errors)
)
ensure_latest_article_revision(
workspace, config["article_id"], config["article_revision"]
)
source = build_registration_source(workspace, config)
payload_hash = registration_payload_hash(config, source)
registrations = load_all_registrations(workspace)
for package in registrations:
if package["request_id"] != config["request_id"]:
continue
if package["payload_sha256"] == payload_hash:
print(json.dumps(_output(package, "duplicate"), ensure_ascii=False, indent=2))
return 0
raise DraftDataError(
"request_id is already used for a different draft registration"
)
validate_approval_timing(config, source, created_at)
started = set()
saved = set()
for event in read_events(workspace):
key = (
event.get("article_id"),
event.get("article_revision"),
event.get("registration_path"),
)
if event.get("event_type") == "note_draft_started":
started.add(key)
elif event.get("event_type") == "note_draft_saved":
saved.add(key)
target_keys = {
key
for key in started | saved
if key[0] == config["article_id"] and key[1] == config["article_revision"]
}
if any(key in saved for key in target_keys):
raise DraftDataError(
"this article revision already has a saved private note draft"
)
if any(key in started and key not in saved for key in target_keys):
raise DraftDataError(
"this article revision has an unresolved external write"
)
revisions = [
int(package["registration_revision"])
for package in registrations
if package["article_id"] == config["article_id"]
]
revision = max(revisions, default=0) + 1
relative = (
f"articles/note-drafts/{config['article_id']}"
f"-registration-r{revision:03d}.json"
)
package = build_registration_package(
config,
source,
registration_revision=revision,
created_at=created_at,
registration_path=relative,
)
ensure_store(workspace)
path = workspace / relative
write_new_text(path, json_text(package))
final_errors, _ = validate_note_draft_data(workspace)
if final_errors:
try:
path.unlink()
except FileNotFoundError:
pass
raise DraftDataError(
"saved registration failed validation: " + "; ".join(final_errors)
)
print(json.dumps(_output(package, "created"), ensure_ascii=False, indent=2))
return 0
except (OSError, UnicodeError, DraftDataError, json.JSONDecodeError) as exc:
print(
json.dumps({"status": "error", "error": str(exc)}, ensure_ascii=False),
file=sys.stderr,
)
return 2
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: d9d613f76bf70ad71986167bb67aa85c762df282ffffd2e58a9f7bb5794c2e59