Build / Build (push) Successful in 1m7s
Starts the completion program (docs/ROADMAP.md, "Owner decisions on finishing everything", 2026-10-17). - Dead code: the commented-out collAnon blocks (discussions, seeding, admin user lists, HTTP/3, the old signature middleware), the empty PrivaPubWorkersConfiguration, PublicAvatarUsersService and UserPolicyType, unused helpers, the second IPasswordHasher registration, the PasswordGenerator package, SignUpAsync/LoginAsync's unused invitation parameters. "Starting PrivaPub"; a signed-in login is sent to "/", not to "/discussions". - Stored fields nothing read: RootUser.Contacts and ResetPasswordToken*, the local Avatar.AvatarServer, EmailRecovery.RecoveryCode/RequestIP/CreationDate, MongoSettings.LogsDatabase, and AppConfiguration's upload/discussion keys, RequiresFirstTimeSetup and Version (old documents still load: MongoDB.Entities ignores extra elements). DmPost's indexes are no longer made. 49 collAnon keys leave FieldsNameResource in every language. - /clientapi/data/current-version answers the build's ref. UsersIds is a list that can't throw, and the admin routes leave the administrator out without mutating the request. - deploy.yml checks SecureMode on a name no persona can have, and the browser redirect on the directory's first local persona: @thepra is the administrator's own now. - Town: decePub's e2e remnants (expect, client.jsonl, the decePub column) and town/tests go; the dead gaps/load commands too. Mobilizon no longer keeps an event for a deleted test. - tools/pasture/sweep.sh runs every peer's scenario, batch by batch, as CLAUDE.md asks before a change to what PrivaPub sends. - Docs: CLAUDE.md's repo map, route table (every frozen route) and stale lines; ROADMAP's status (setup, v1.25.0, v1.26.0, the program C), the 2026-10-17 decisions, and dated notes where earlier text no longer holds; FEDERATION.md's FEP list (7888, f228, 7628, ae0c and 8967 supported) and the deploy's persona. Verified: dotnet build PrivaPub.sln -c Release (0 errors, no new warnings); bash -n on the touched scripts; py_compile on the town; the pasture's gts, mastodon and lemmy scenarios on this build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
71 lines
2.9 KiB
Python
71 lines
2.9 KiB
Python
"""The town's command line. Run through tools/pasture/town.sh.
|
|
|
|
selftest <peer>... each driver against its own server: accounts, posts, likes, replies, polls, edits,
|
|
deletes, and that its database view agrees with its API
|
|
drive <peer> <user> <verb> '<json>' one action as one town account, printed as JSON
|
|
stored <peer> <uri>... what a peer holds of each object (from its database, never fetching)
|
|
seen <peer> <user> <uri>... what one account can see of each object
|
|
renew <peer>... its accounts signed in again (after a PrivaPub restore ends every session)
|
|
plan <spec> the deterministic plan of a spec, printed as JSON lines
|
|
seed <spec> replays a spec's plan against the pasture, writing out/<run>/ledger.jsonl
|
|
check [run] sweeps every peer for what the ledger expects
|
|
report [run...] out/<run>/report.html; several runs (a village and pairs) in one matrix
|
|
backlog [run] [--write] docs/INTEROP-BACKLOG.md from the latest results
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
|
|
from dialects import DRIVERS, driver # noqa: E402
|
|
from dialects.base import Account, PostSpec # noqa: E402
|
|
import state # noqa: E402
|
|
|
|
|
|
def main(argv):
|
|
if not argv or argv[0] in ("-h", "--help", "help"):
|
|
print(__doc__)
|
|
return 0
|
|
cmd, args = argv[0], argv[1:]
|
|
if cmd == "selftest":
|
|
import selftest
|
|
return selftest.run(args or [p for p in DRIVERS])
|
|
if cmd == "drive":
|
|
peer, user, verb = args[0], args[1], args[2]
|
|
params = json.loads(args[3]) if len(args) > 3 else {}
|
|
s = state.session(peer, user)
|
|
d = driver(peer)
|
|
if verb == "post":
|
|
made = d.post(s, PostSpec(**params))
|
|
print(json.dumps(made.__dict__))
|
|
else:
|
|
result = getattr(d, verb)(s, **params)
|
|
print(json.dumps(result if not hasattr(result, "__dict__") else result.__dict__, default=str, ensure_ascii=False))
|
|
return 0
|
|
if cmd == "stored":
|
|
rows = driver(args[0]).stored(args[1:])
|
|
print(json.dumps({u: {k: v for k, v in r.__dict__.items() if k != "raw"} for u, r in rows.items()}, default=str))
|
|
return 0
|
|
if cmd == "renew":
|
|
# a peer's town accounts signed in again (a PrivaPub restore ends every session): new tokens, nothing else
|
|
for platform in args:
|
|
stored = state.sessions(platform)
|
|
state.remember(driver(platform).provision([s.account for s in stored]))
|
|
print(f"{platform}: {len(stored)} accounts signed in again")
|
|
return 0
|
|
if cmd == "seen":
|
|
s = state.session(args[0], args[1])
|
|
print(json.dumps(driver(args[0]).seen(s, args[2:])))
|
|
return 0
|
|
if cmd in ("plan", "seed", "check", "report", "backlog"):
|
|
module = __import__(cmd if cmd not in ("plan",) else "gen")
|
|
return module.main(args)
|
|
print(f"unknown command {cmd}", file=sys.stderr)
|
|
return 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv[1:]) or 0)
|