oficina / home Public

Specify complete Home compatibility checker and readonly constraints

Paul Campbell pushed by paul@keymail.dev 2214be15c9768dc3ba57dbcd33861c7e388a4909 parent 7e282e2
6 files changed, +953 −0
  • implementation/compatibility-checker/audit.json +461 −0
  • implementation/compatibility-checker/probe/observation.json +28 −0
  • implementation/compatibility-checker/probe/readonly_probe_test.go.txt +54 −0
  • implementation/compatibility-checker/probe/reproduction.json +18 −0
  • implementation/compatibility-checker/proposal.json +386 −0
  • implementation/compatibility-checker/source-validation.json +6 −0

CI passed — run details

diff --git a/implementation/compatibility-checker/audit.json b/implementation/compatibility-checker/audit.json
new file mode 100644
index 0000000..aeefe5f
--- /dev/null
+++ b/implementation/compatibility-checker/audit.json
@@ -0,0 +1,461 @@
+{
+ "version": 1,
+ "kind": "read-only-source-audit",
+ "home_revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "source_root": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare",
+ "decision": {
+ "existing_complete_checker": false,
+ "existing_mounted_checker": false,
+ "config_facts_collector_is_complete_checker": false,
+ "recommendation": "Specify and review one complete checker slice, using a pure shared config parser internally. Do not count an independently shipped unmounted facts helper as checker delivery. Approved text authorizes a separate small implementation/review slice; it does not define the remaining wire, digest or DB compatibility contract.",
+ "no_live_calls": true,
+ "no_source_edits": true,
+ "no_tests_run_for_read_only_audit": true,
+ "no_fable_invoked": true
+ },
+ "requirements": [
+ {
+ "requirement": "Bounded private result: exact origins, active public operator/assertion/roster fingerprints, consumer-manifest digest; no network, sessions, DB/key/authority changes.",
+ "source": [
+ "S1"
+ ]
+ },
+ {
+ "requirement": "Fresh selected-serving-release checker against existing DB under fence/lease, exact artifact/config/key pins; app owns format/key/authorization compatibility. Earlier operator success and HTTP health cannot substitute.",
+ "source": [
+ "P1"
+ ]
+ },
+ {
+ "requirement": "Existing regular pinned DB, no creation/migration repair; application identity, expected role/origin, migration ledger and required additive versions verified.",
+ "source": [
+ "S2"
+ ],
+ "qualification": "Mutation engine transaction/secure_delete rules are not permission for checker writes."
+ }
+ ],
+ "reusable_primitives": [
+ {
+ "symbols": [
+ "home.LoadOrigins",
+ "home.LoadRuntime",
+ "home.loadRosterRuntime",
+ "home.rosterKeyID"
+ ],
+ "source": [
+ "S3",
+ "S5",
+ "S6"
+ ],
+ "reuse": "Exact current role, origin, consumer and key validation. Refactor shared pure parsing with explicit protected-snapshot input; preserve runtime behavior and LookupEnv presence semantics.",
+ "gap": "Private Runtime fields; no complete public facts API. LoadRuntime calls LoadSecrets, which constructs mailer. It does not itself open DB."
+ },
+ {
+ "symbols": [
+ "operator.Pins",
+ "operator.NewCredential",
+ "operator.NewDirectory",
+ "operator.keyID"
+ ],
+ "source": [
+ "S7",
+ "S8",
+ "S9",
+ "S10"
+ ],
+ "reuse": "Explicit configured public pins; SHA256 exact public bytes encoded lower hex; existing key-role separation checks.",
+ "gap": "No assembled operator runtime config or checker key-role output registry. Owner-seed signer and directory provisioner signer are distinct roles from command-authorizer and assertion/roster keys."
+ },
+ {
+ "symbols": [
+ "operator.Directory.Inspect"
+ ],
+ "source": [
+ "S11"
+ ],
+ "reuse": "Bounded signed challenge and read-transaction observation pattern.",
+ "gap": "Only generation and proposed next team; does not validate/report compatibility config facts. Do not repurpose its signed purpose/output."
+ },
+ {
+ "symbols": [
+ "operator.newBoundDatabase",
+ "operator.boundConnector.Connect"
+ ],
+ "source": [
+ "S12",
+ "S13"
+ ],
+ "reuse": "Existing-file device/inode/path/actual SQLite descriptor proof, one connection, deadline refusal.",
+ "gap": "Unmounted and private; requires separately verified launch authority. Uses mode=rw and requires O_RDWR actual main descriptor. Readonly DSN substitution would fail its present proof. No evidence this connector promises zero DB/WAL/SHM writes when used as checker."
+ },
+ {
+ "symbols": [
+ "operator.Engine.Execute"
+ ],
+ "source": [
+ "S14"
+ ],
+ "reuse": "Connection checks provide reference for FK/WAL and bounded DB validation.",
+ "gap": "Not usable as checker execution: BEGIN IMMEDIATE and durable operation/sequence/receipt mutations."
+ },
+ {
+ "symbols": [
+ "home.Runtime.Schema",
+ "operator.CredentialSchema",
+ "operator.DirectorySchema"
+ ],
+ "reuse": "Role-specific embedded schema requirements available to inspect.",
+ "gap": "Do not call migrate.Apply. No existing exported checker that compares ledger and rejects incompatible future/partial schemas."
+ },
+ {
+ "symbols": [
+ "operator.ActivationEvidence.ManifestDigest"
+ ],
+ "source": [
+ "S15",
+ "S16"
+ ],
+ "reuse": "Existing downstream field is canonical 32-byte raw-base64url token.",
+ "gap": "Validation checks shape only; no manifest digest producer or canonicalization algorithm."
+ }
+ ],
+ "already_authorized_implementation_scope": [
+ "Pure shared configuration parsing and facts gathering needed by the approved checker, with deterministic tests and no process/authority side effects.",
+ "Reuse existing public key byte hashing and exact role validation; preserve private/public separation and never emit secret material.",
+ "Read-only validation of existing role/DB compatibility is required, but its exact schema acceptance matrix and no-write opening seam must be defined/reviewed before claiming the full checker."
+ ],
+ "unresolved_contract_choices": [
+ {
+ "id": "manifest-digest",
+ "existing": "ActivationEvidence requires CanonicalToken (32-byte raw-base64url); key IDs elsewhere use lowercase hex SHA256.",
+ "needed": "Choose exact manifest bytes: normalized validated ID->origin map versus literal decoded JSON. Define ordering/encoding/empty or absent directory-role value. No existing approved algorithm found; do not silently use key-ID hex for ManifestDigest."
+ },
+ {
+ "id": "active-key-roles",
+ "existing": "Distinct command-authorizer, credential owner-seed signer, directory provisioning signer, browser assertion keys and roster keys; constructors enforce subsets of separation.",
+ "needed": "Exact role-labelled fields, active signer versus accepted verification key set, absent/disabled roles, bounds, and binding to actual runtime operator configuration. No new env variable names inferred."
+ },
+ {
+ "id": "db-compatibility",
+ "existing": "Required existingDB/schema/role/key checks; embedded role migrations; no complete checker.",
+ "needed": "Exact supported ledger versions/app identity evidence; checks for stored operator role/origin and post-seed state; correct DEK/pepper/signin compatibility and empty DB handling without synthesizing authority or leaking data. Config fingerprint equality alone does not prove existing ciphertext decryptability or authorization semantics."
+ },
+ {
+ "id": "no-write-db-open",
+ "existing": "Pinned connector is mode=rw and demands writable main descriptor.",
+ "needed": "Specify whether approved no DB changes means no logical writes plus allowed SQLite housekeeping, or byte-level no mutation; prove actual existing DB/WAL/SHM behavior. Do not bypass descriptor proof via unchecked readonly sql.Open or immutable snapshot."
+ },
+ {
+ "id": "launch-output",
+ "existing": "Approved immutable protected environment and fixed command under maintenance; no mounted adapter here.",
+ "needed": "Use reviewed platform launch/receipt binding, private bounded output, failure and freshness handling. No new signed output envelope, env boolean authority or arbitrary command. Facts collector output alone is not launch authority."
+ }
+ ],
+ "proposed_complete_slice_boundaries": {
+ "configuration": "Internal pure parser shared with serving LoadRuntime; no mailer, DB, process or network construction. Typed configured key roles; exact agreed digest convention.",
+ "database": "One bounded existing-DB validation path with reviewed identity/no-write semantics and explicit role/schema/key acceptance matrix; no migrations or Engine.Execute.",
+ "command": "Fixed non-serving dispatch before normal startup, wired only to separately reviewed immutable launch adapter and private bounded result. If launch dependency is unavailable, mark complete command delivery blocked rather than claim a helper is the checker.",
+ "success": "Only after all configured facts and DB compatibility checks pass; fresh invocation under retained fence/lease. Failure emits no partial/private payload or success evidence."
+ },
+ "existing_tests": {
+ "internal/operator/inspect_test.go": [
+ {
+ "line": 15,
+ "symbol": "TestInspectDoesNotInitializeOrReserveAuthority"
+ },
+ {
+ "line": 59,
+ "symbol": "TestInspectWrongBindingsAndMutableInputRefuse"
+ }
+ ],
+ "internal/operator/open_linux_test.go": [
+ {
+ "line": 41,
+ "symbol": "TestBoundDatabaseSubprocess"
+ },
+ {
+ "line": 344,
+ "symbol": "TestBoundDatabaseEngineSubprocess"
+ }
+ ],
+ "internal/operator/engine_test.go": [
+ {
+ "line": 82,
+ "symbol": "TestEngineCommitsOnceAndRecoversExpiredResultPrivately"
+ },
+ {
+ "line": 117,
+ "symbol": "TestEngineFailureRollsBackMutationReceiptAndSequence"
+ },
+ {
+ "line": 156,
+ "symbol": "TestEngineConcurrentRetryHasOneMutation"
+ },
+ {
+ "line": 183,
+ "symbol": "TestEngineForeignKeyEnforcementUsesMutationConnection"
+ },
+ {
+ "line": 200,
+ "symbol": "TestEngineRefusesExpiredNewAndCorruptExistingResult"
+ }
+ ],
+ "internal/home/runtime_test.go": [
+ {
+ "line": 38,
+ "symbol": "TestRuntimeKeepsLegacyAndRequiresExplicitRoles"
+ },
+ {
+ "line": 49,
+ "symbol": "TestDirectoryRuntimeNeedsNoCredentialMaterial"
+ },
+ {
+ "line": 68,
+ "symbol": "TestCredentialRuntimeValidatesManifestAndSigningKey"
+ },
+ {
+ "line": 91,
+ "symbol": "TestDirectoryRuntimeRefusesMalformedKeys"
+ },
+ {
+ "line": 102,
+ "symbol": "TestRuntimeEncodedPlatformConfiguration"
+ }
+ ],
+ "internal/home/keys_test.go": [
+ {
+ "line": 47,
+ "symbol": "TestLoadSealerRefusals"
+ },
+ {
+ "line": 64,
+ "symbol": "TestLoadSealerAcceptsA32ByteKey"
+ },
+ {
+ "line": 75,
+ "symbol": "TestLoadSecretsAcceptsCompleteConfig"
+ },
+ {
+ "line": 98,
+ "symbol": "TestLoadSecretsRefusesEachMissingSecret"
+ },
+ {
+ "line": 113,
+ "symbol": "TestLoadSecretsRefusesMalformedSecrets"
+ },
+ {
+ "line": 130,
+ "symbol": "TestLoadSecretsRefusesWithoutSMTPHostOrFrom"
+ },
+ {
+ "line": 150,
+ "symbol": "TestLoadSecretsRefusesEmptyDBPath"
+ },
+ {
+ "line": 164,
+ "symbol": "TestLoadSecretsRefusesAllZeroKeys"
+ },
+ {
+ "line": 182,
+ "symbol": "TestNewRefusesIncompleteWiring"
+ }
+ ],
+ "internal/home/roster_runtime_test.go": [
+ {
+ "line": 27,
+ "symbol": "TestRosterRuntimeModeKeyAndRoleMatrix"
+ },
+ {
+ "line": 62,
+ "symbol": "TestRosterRuntimeStrictPrivateEncoding"
+ },
+ {
+ "line": 80,
+ "symbol": "TestRosterDirectConstructorsAndEmptySchema"
+ }
+ ]
+ },
+ "required_acceptance_tests": [
+ "Parser parity with actual serving configuration including credential/directory/legacy, encoded platform values, disabled roster and unset-versus-empty settings.",
+ "Digest determinism and exact downstream raw-base64url shape; ordering/whitespace changes follow reviewed semantics; changed origin changes digest.",
+ "All active/accepted public key roles accounted for; collisions, wrong role/pin, absent private config refuse; canaries prove no private bytes in result/errors/logs.",
+ "No listener, mail send, session mint, authority journal mutation, migration or DB creation; actual subprocess with denied network and controlled inherited descriptors.",
+ "Synthetic existing credential/directory DBs: correct role/schema/key passes; wrong role/origin/key, partial/future/corrupt ledger refuses; existing identities/owners/generation/sequence unchanged.",
+ "Actual DB/WAL/SHM before/after evidence matches reviewed no-write contract, including hot WAL, readonly permissions and failed checks.",
+ "Replacement-path/open-restore race, hardlinks, expired deadline and actual descriptor mismatch refuse using existing connector proof or explicitly reviewed extension.",
+ "Selected artifact/environment/attempt mismatch and stale checker output cannot resume; prior action success and HTTP health cannot bypass checker.",
+ "Mutations removing schema/key verification, role separation or digest comparison must fail meaningful tests."
+ ],
+ "source_evidence": [
+ {
+ "id": "S1",
+ "file": "implementation/home-provisioner.md",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/implementation/home-provisioner.md",
+ "sha256": "6fc38e7ee071f2c41446d6c254591ac6999e90eb043e02bb418f6f4747e4deb5",
+ "line": 256,
+ "end_line": 274,
+ "excerpt": "Use maintenance's immutable protected environment binding and a fixed non-serving\napplication compatibility checker against that snapshot. The Home checker reports\nonly exact origins, active public operator/assertion/roster key fingerprints and\nconsumer-manifest digest. The Docs checker reports exact TeamMode bindings, verified\nprovisioning record digest, generation and SHA256 of the canonical bearer already\npresent in protected config. These are bounded private results, never public logs.\nCheckers make no network calls, mint no sessions and change no DB/key/authority.\nThey require separate small implementation/review slices; no current API is claimed\nto supply these application-specific facts. Existing secret fingerprints are compared\nprivately to enrolled fingerprints, without copying existing private keys out. Dial only configured\ncanonical HTTPS hosts with normal certificate validation, no redirects unless the\nspecific sign-in probe validates every expected hop. Compare full expected version\nin body/header and current platform route/alias mapping. Store bounded response\ndigests, typed binding facts and timestamps in the encrypted signed journal; token,\nemail, assertion and unrelated response content are never retained in evidence.\n\n## Activation gate and pending roster integration\n\nAn activation authorization signs exact consumer/team/app/audience, generation,"
+ },
+ {
+ "id": "S2",
+ "file": "implementation/home-operator-seed.md",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/implementation/home-operator-seed.md",
+ "sha256": "e1d14379b8642e3ada7d355b0e834a3d06acb8f662a6a142e9d738af16ac856b",
+ "line": 247,
+ "end_line": 265,
+ "excerpt": "Open an existing regular database with creation disabled, through the pinned\nplatform path. Check application identity, expected role/origin, migration ledger\nand required additive schema versions before any action. Never call the general\nweb startup migrator to repair an unexpected DB from this command. The deployment\napplies reviewed role-specific additive migrations before operator execution.\n\nAcquire one dedicated database/sql connection. Set foreign_keys ON before beginning\nand read it back as 1 on that exact connection; pooled connections cannot substitute\nfor this check. Also require secure_delete ON, expected journal configuration,\nno foreign_key_check violations, and the verified transport fence/lease. Take an\nimmediate write transaction with a bounded lock timeout; all idempotency, generation,\nsequence, owner receipt and registry preconditions are rechecked inside it. Do not\nperform network work while holding the lock. Refuse wrong clocks, time rollback\nrelative to persisted operator completion time, exhausted counters or corrupt rows.\nWrite all related authority and audit rows together. Close/checkpoint through the\nsupported transport protocol before resume; an uncertain commit remains fenced\nuntil querying the same operation establishes its outcome.\n\nNo success path changes existing sessions, assertion keys, content encryption,"
+ },
+ {
+ "id": "S3",
+ "file": "internal/home/runtime.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/runtime.go",
+ "sha256": "04ad2e232f37b4027ba1900bf0ff75de805f91fd360af464be13ada8d83023ab",
+ "line": 38,
+ "end_line": 145,
+ "excerpt": "func LoadRuntime(dbPath string, logger *slog.Logger) (Runtime, error) {\n\tvar cfg Runtime\n\tvar err error\n\tcfg.origins, err = LoadOrigins()\n\tif err != nil {\n\t\treturn Runtime{}, err\n\t}\n\tcfg.role = os.Getenv(\"HOME_ROLE\")\n\tif cfg.role != \"directory\" {\n\t\tcfg.roster, err = loadRosterRuntime(cfg.role, nil)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t}\n\tswitch cfg.role {\n\tcase \"\":\n\t\tcfg.secrets, err = LoadSecrets(dbPath, logger)\n\t\treturn cfg, err\n\tcase \"credential\":\n\t\tcfg.secrets, err = LoadSecrets(dbPath, logger)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tencodedPrivate := os.Getenv(\"HOME_ASSERTION_KEY\")\n\t\tif len(encodedPrivate) > 4096 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\traw, err := base64.StdEncoding.DecodeString(encodedPrivate)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.signer, err = assertioncrypto.UnmarshalKeypair(raw)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tif cfg.signer.SignPriv.D.Sign() <= 0 || cfg.signer.SignPriv.D.Cmp(elliptic.P256().Params().N) >= 0 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tpub := cfg.signer.SignPub()\n\t\tsum := sha256.Sum256(pub)\n\t\tcfg.keyID = hex.EncodeToString(sum[:])\n\t\tcfg.keys = map[string][]byte{cfg.keyID: pub}\n\t\trawManifest, err := exchangeJSON(\"HOME_CONSUMERS\", 8192)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\t// Sixteen pilot origins keep the exact CSP manifest within ordinary header\n\t\t// limits. Production registration needs a separately reviewed scalable path.\n\t\tif len(rawManifest) > 8192 || json.Unmarshal([]byte(rawManifest), &cfg.consumers) != nil || len(cfg.consumers) == 0 || len(cfg.consumers) > 16 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tfor id, origin := range cfg.consumers {\n\t\t\tif !consumerName(id) {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t\tif _, err = assertion.NewVerifier(cfg.origins.Credential, origin, cfg.keys); err != nil {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t}\n\t\tif cfg.consumers[\"directory\"] != cfg.origins.Directory {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\tcase \"directory\":\n\t\tif dbPath == \"\" || os.Getenv(\"HOME_ASSERTION_KEY\") != \"\" {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.secrets.Sealer, err = LoadSealer()\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tvar encoded map[string]string\n\t\traw, err := exchangeJSON(\"HOME_ASSERTION_KEYS\", 4096)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tif len(raw) > 4096 || json.Unmarshal([]byte(raw), &encoded) != nil || len(encoded) == 0 || len(encoded) > 8 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.keys = make(map[string][]byte, len(encoded))\n\t\tfor kid, value := range encoded {\n\t\t\tkey, err := base64.StdEncoding.DecodeString(value)\n\t\t\tif err != nil {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t\tcfg.keys[kid] = key\n\t\t}\n\t\tif _, err = assertion.NewVerifier(cfg.origins.Credential, cfg.origins.Directory, cfg.keys); err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.roster, err = loadRosterRuntime(cfg.role, cfg.keys)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\tdefault:\n\t\treturn Runtime{}, errExchangeConfig\n\t}\n\treturn cfg, nil\n}\nfunc consumerName(s string) bool {\n\tif len(s) == 0 || len(s) > 64 {\n\t\treturn false\n\t}\n\tfor _, b := range []byte(s) {\n\t\tif !(b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' || b >= '0' && b <= '9' || b == '_' || b == '-') {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true"
+ },
+ {
+ "id": "S4",
+ "file": "internal/home/keys.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/keys.go",
+ "sha256": "4b4cb1c250c6b9827df4871108f4baa2ddde45976457c112bb70a9657fa41b48",
+ "line": 118,
+ "end_line": 172,
+ "excerpt": "func LoadSecrets(dbPath string, logger *slog.Logger) (Secrets, error) {\n\tif logger == nil {\n\t\tlogger = slog.Default()\n\t}\n\n\t// SQLite treats an empty filename as a private temporary database:\n\t// the app comes up, works, and loses every person on restart. There\n\t// is no warning for this anywhere below us, which is why it is\n\t// checked here.\n\tif strings.TrimSpace(dbPath) == \"\" {\n\t\treturn Secrets{}, errors.New(\"no database path: set Options.DBPath or pass -db, or SQLite opens a private temporary database and every person is lost on restart\")\n\t}\n\n\tvar s Secrets\n\tvar err error\n\n\t// Through LoadSealer rather than beside it, so HOME_DEK is read in\n\t// one place. Two readers of the same variable is how one of them\n\t// ends up with a check the other does not have.\n\ts.Sealer, err = LoadSealer()\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\n\tpepper, err := key32(\"HOME_PEPPER\")\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\ts.Pepper = pepper[:]\n\n\ts.SigninKey, err = key32(\"HOME_SIGNIN_KEY\")\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\n\t// mail.FromEnv falls back to mail.Logged with a warning when HOST or\n\t// FROM is absent, and Logged's Send logs \"to\", to \u2014 an address into\n\t// platform-held logs on every single sign-in. A warning is not\n\t// enough: that log is storage we cannot grep or redact, so this is\n\t// the one fallback we refuse instead of accept.\n\t//\n\t// CARLOS_SMTP_PASS is a different failure and is refused for a\n\t// different reason, so the message below distinguishes them. It\n\t// leaks nothing: with HOST and FROM set, FromEnv returns the SMTP\n\t// sender whether or not PASS is present. What a missing PASS costs\n\t// is delivery \u2014 every link fails at send time on an app that\n\t// otherwise looks healthy. (It is inert without CARLOS_SMTP_USER,\n\t// which `carlos email enable` delivers alongside it; refusing on\n\t// PASS is a bet that the platform sets both or neither.)\n\t//\n\t// Deliberately no loopback relaxation. Sheets' LoadAuthEnv allows\n\t// one for local development, keyed on its instance origin being an\n\t// http loopback host. The home has no origin variable at this step,\n\t// so the equivalent carve-out would have to invent one, and a\n\t// carve-out that turns off the leak guard is not a thing to invent"
+ },
+ {
+ "id": "S5",
+ "file": "internal/home/origins.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/origins.go",
+ "sha256": "dc98e1a428ff5703a08ce24e674a121eb450e9155040e1854319d2449d9be851",
+ "line": 26,
+ "end_line": 67,
+ "excerpt": "func LoadOrigins() (Origins, error) {\n\tcredential, haveCredential := os.LookupEnv(\"HOME_CREDENTIAL_ORIGIN\")\n\tdirectory, haveDirectory := os.LookupEnv(\"HOME_DIRECTORY_ORIGIN\")\n\tif !haveCredential && !haveDirectory {\n\t\treturn Origins{Origin, directoryOrigin}, nil\n\t}\n\torigins := Origins{credential, directory}\n\tif !haveCredential || !haveDirectory {\n\t\treturn Origins{}, errOrigins\n\t}\n\treturn origins, origins.validate()\n}\n\nfunc originHost(origin string) (string, error) {\n\tu, err := url.Parse(origin)\n\tif err != nil || u.Scheme != \"https\" || u.User != nil || u.Host == \"\" || origin != \"https://\"+u.Host || u.Host != strings.ToLower(u.Host) || net.ParseIP(u.Host) != nil {\n\t\treturn \"\", errOrigins\n\t}\n\tif len(u.Host) > 253 {\n\t\treturn \"\", errOrigins\n\t}\n\tlabels := strings.Split(u.Host, \".\")\n\tif len(labels) < 2 {\n\t\treturn \"\", errOrigins\n\t}\n\tfor _, label := range labels {\n\t\tif len(label) == 0 || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' {\n\t\t\treturn \"\", errOrigins\n\t\t}\n\t\tfor _, c := range label {\n\t\t\tif !(c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '-') {\n\t\t\t\treturn \"\", errOrigins\n\t\t\t}\n\t\t}\n\t}\n\treturn u.Host, nil\n}\n\nfunc (o Origins) validate() error {\n\tcredential, err := originHost(o.Credential)\n\tif err != nil {\n\t\treturn err"
+ },
+ {
+ "id": "S6",
+ "file": "internal/home/roster_runtime.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/roster_runtime.go",
+ "sha256": "5e2ed41df26b1342834fe6996b5df901a2b05e9f4f41bb6afc98c6e8a7bd3c3c",
+ "line": 54,
+ "end_line": 105,
+ "excerpt": "func loadRosterRuntime(role string, credentialKeys map[string][]byte) (rosterRuntime, error) {\n\tmode, modeSet := os.LookupEnv(\"HOME_ROSTER_MODE\")\n\tencoded, keySet := os.LookupEnv(\"HOME_ROSTER_KEY\")\n\tif role != \"directory\" {\n\t\tif modeSet || keySet {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\treturn rosterRuntime{}, nil\n\t}\n\tif !modeSet {\n\t\tmode = \"disabled\"\n\t}\n\tif mode == \"disabled\" {\n\t\tif keySet {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\treturn rosterRuntime{mode: mode}, nil\n\t}\n\tif mode != \"serve\" || !keySet || len(encoded) > 4096 {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\traw, err := base64.StdEncoding.Strict().DecodeString(encoded)\n\tif err != nil || base64.StdEncoding.EncodeToString(raw) != encoded {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tvar fields struct {\n\t\tSign string `json:\"sign_priv_d\"`\n\t\tBox string `json:\"box_priv_d\"`\n\t}\n\tif json.Unmarshal(raw, &fields, json.RejectUnknownMembers(true)) != nil {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tfor _, s := range []string{fields.Sign, fields.Box} {\n\t\tb, e := hex.DecodeString(s)\n\t\tif e != nil || len(b) != 32 || hex.EncodeToString(b) != s {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\td := new(big.Int).SetBytes(b)\n\t\tif d.Sign() <= 0 || d.Cmp(elliptic.P256().Params().N) >= 0 {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t}\n\tkey, err := family.UnmarshalKeypair(raw)\n\tif err != nil || !validRosterKey(key) {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tcfg := rosterRuntime{mode: mode, signer: key, keyID: rosterKeyID(key)}\n\tif !cfg.valid(role, credentialKeys) {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\treturn cfg, nil\n}"
+ },
+ {
+ "id": "S7",
+ "file": "internal/operator/protocol.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/protocol.go",
+ "sha256": "332ff9ccbdee79778486a49d54cd2c7c7f36fc0fd28a2770ee4a0f553316dba3",
+ "line": 54,
+ "end_line": 58,
+ "excerpt": "type Pins struct {\n\tRole, Origin, Installation, Registry, Device string\n\tPublicKey string\n\tActions []string\n}"
+ },
+ {
+ "id": "S8",
+ "file": "internal/operator/protocol.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/protocol.go",
+ "sha256": "332ff9ccbdee79778486a49d54cd2c7c7f36fc0fd28a2770ee4a0f553316dba3",
+ "line": 118,
+ "end_line": 118,
+ "excerpt": "func keyID(b []byte) string { h := sha256.Sum256(b); return hex.EncodeToString(h[:]) }"
+ },
+ {
+ "id": "S9",
+ "file": "internal/operator/directory.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/directory.go",
+ "sha256": "4071f042ee858f0b71aff414b7e0a2cc1ca1bf2598d941e14544db94bf90cf4e",
+ "line": 82,
+ "end_line": 121,
+ "excerpt": "func NewDirectory(engine *Engine, owner *OwnerVerifier, signer *family.Keypair, keys []roster.Key, policy directorydata.Config) (*Directory, error) {\n\tif engine == nil || engine.verifier.pins.Role != \"directory\" || owner == nil || owner.directory != engine.verifier.pins.Origin || !signingKey(signer) || len(keys) == 0 || len(keys) > 8 {\n\t\treturn nil, ErrRefused\n\t}\n\tnames, e := directorydata.New(engine.db, engine.sealer, policy)\n\tif e != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tseen := map[string]bool{}\n\tfor _, k := range [][]byte{engine.verifier.key, owner.key, signer.SignPub()} {\n\t\tif seen[string(k)] {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tseen[string(k)] = true\n\t}\n\tids := map[string]bool{}\n\tfor _, k := range keys {\n\t\tp, e := public(k.Public)\n\t\tif e != nil || !atom(k.ID, 64) || ids[k.ID] || seen[string(p)] {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tids[k.ID] = true\n\t\tseen[string(p)] = true\n\t}\n\td := &Directory{engine, owner, signer, append([]roster.Key(nil), keys...), names, policy, map[string]bool{}}\n\td.policy.Apps = append([]string(nil), policy.Apps...)\n\tfor _, app := range policy.Apps {\n\t\td.apps[app] = true\n\t}\n\treturn d, nil\n}\nfunc atom(s string, max int) bool {\n\tif len(s) == 0 || len(s) > max {\n\t\treturn false\n\t}\n\tfor _, c := range s {\n\t\tif !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' || c == '-') {\n\t\t\treturn false\n\t\t}\n\t}"
+ },
+ {
+ "id": "S10",
+ "file": "internal/operator/credential.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/credential.go",
+ "sha256": "327f2e53728f919b1cc63697816dd3898c6393b8bc003436b78a43bd6c5895fb",
+ "line": 34,
+ "end_line": 50,
+ "excerpt": "func NewCredential(engine *Engine, directory string, signer *family.Keypair, browserPublicKeys [][]byte, resolve PersonResolver) (*Credential, error) {\n\tif engine == nil || engine.verifier.pins.Role != \"credential\" || !Origin(directory) || directory == engine.verifier.pins.Origin || !signingKey(signer) || resolve == nil || len(browserPublicKeys) == 0 || len(browserPublicKeys) > 8 || bytes.Equal(signer.SignPub(), engine.verifier.key) {\n\t\treturn nil, ErrRefused\n\t}\n\tfor _, key := range browserPublicKeys {\n\t\tif _, e := public(base64.RawURLEncoding.EncodeToString(key)); e != nil {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tif bytes.Equal(key, signer.SignPub()) || bytes.Equal(key, engine.verifier.key) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t}\n\treturn &Credential{engine, directory, signer, resolve}, nil\n}\nfunc (c *Credential) Execute(ctx context.Context, raw []byte) ([]byte, error) {\n\treturn c.engine.Execute(ctx, raw, func(ctx context.Context, conn *sql.Conn, r Request) ([]byte, error) {\n\t\tvar in OwnerInput"
+ },
+ {
+ "id": "S11",
+ "file": "internal/operator/inspect.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/inspect.go",
+ "sha256": "53f03642dd419e369efbf5decfff291ce5b54c6efe91e5156c2c435b223fa541",
+ "line": 72,
+ "end_line": 132,
+ "excerpt": "func (d *Directory) Inspect(ctx context.Context, raw []byte) ([]byte, error) {\n\tif d == nil || d.engine == nil {\n\t\treturn nil, ErrRefused\n\t}\n\te := d.engine\n\tchallenge, err := e.verifier.verifyInspect(raw, e.now())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\tc, err := e.db.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer c.Close()\n\tif _, err = c.ExecContext(ctx, \"BEGIN\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer c.ExecContext(context.Background(), \"ROLLBACK\")\n\tvar count int\n\tif err = c.QueryRowContext(ctx, \"SELECT count(*) FROM directory_operator_state WHERE singleton=1 AND (origin!=? OR installation!=? OR registry!=? OR device!=? OR key_id!=? OR completed_at>?)\", e.verifier.pins.Origin, e.verifier.pins.Installation, e.verifier.pins.Registry, e.verifier.pins.Device, e.verifier.kid, e.now().Unix()).Scan(&count); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif count != 0 {\n\t\treturn nil, ErrRefused\n\t}\n\tvar generation *string\n\trows, err := c.QueryContext(ctx, \"SELECT generation FROM roster_generation WHERE singleton=1\")\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif rows.Next() {\n\t\tvar g string\n\t\tif rows.Scan(&g) != nil || !CanonicalToken(g) {\n\t\t\trows.Close()\n\t\t\treturn nil, ErrUnavailable\n\t\t}\n\t\tgeneration = &g\n\t}\n\terr = rows.Err()\n\tcloseErr := rows.Close()\n\tif err != nil || closeErr != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tid, sqid, err := nextTeam(ctx, c)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = e.verifier.verifyInspect(raw, e.now()); err != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tout, err := encode(Inspection{1, challenge.Challenge, e.now().Unix(), generation, id, sqid})\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = c.ExecContext(ctx, \"COMMIT\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\treturn out, nil\n}"
+ },
+ {
+ "id": "S12",
+ "file": "internal/operator/open_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/open_linux.go",
+ "sha256": "15ba8a2dc975a61d614c39e1cd3f7e7dc24f617140b893610d4954ae87b13c38",
+ "line": 52,
+ "end_line": 81,
+ "excerpt": "func newBoundDatabase(path string, device, inode uint64, deadline time.Time) (*boundDatabase, error) {\n\tif device == 0 || inode == 0 || !deadline.After(time.Now()) {\n\t\treturn nil, ErrRefused\n\t}\n\tpin, id, e := pinExisting(path)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tif id != (fileIdentity{device, inode}) {\n\t\tpin.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tc := &boundConnector{path: path, pin: pin, identity: id, deadline: deadline, sqlite: &sqlite.Driver{}}\n\tdb := sql.OpenDB(c)\n\tdb.SetMaxOpenConns(1)\n\tdb.SetMaxIdleConns(1)\n\treturn &boundDatabase{db, c}, nil\n}\nfunc (b *boundDatabase) close() error {\n\te := b.db.Close()\n\tb.connector.mu.Lock()\n\tdefer b.connector.mu.Unlock()\n\tif b.connector.active {\n\t\treturn ErrUnavailable\n\t}\n\tif x := b.connector.pin.Close(); e == nil {\n\t\te = x\n\t}\n\treturn e\n}"
+ },
+ {
+ "id": "S13",
+ "file": "internal/operator/open_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/open_linux.go",
+ "sha256": "15ba8a2dc975a61d614c39e1cd3f7e7dc24f617140b893610d4954ae87b13c38",
+ "line": 202,
+ "end_line": 283,
+ "excerpt": "func (c *boundConnector) Connect(ctx context.Context) (driver.Conn, error) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tif c.active || ctx.Err() != nil || c.pathMatches() != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tc.checkpoint(\"before-inventory\")\n\tbaseline, e := descriptors()\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tfor _, d := range baseline {\n\t\tif writable(d.flags) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t}\n\tc.checkpoint(\"before-open\")\n\tif c.pathMatches() != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tc.checkpoint(\"before-driver\")\n\tu := url.URL{Scheme: \"file\", Path: c.path}\n\tq := u.Query()\n\tq.Set(\"mode\", \"rw\")\n\tu.RawQuery = q.Encode()\n\tnative, e := c.sqlite.Open(u.String())\n\tif e != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tkeep := false\n\tdefer func() {\n\t\tif !keep {\n\t\t\tnative.Close()\n\t\t}\n\t}()\n\tc.checkpoint(\"after-open\")\n\tcurrent, e := descriptors()\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tmainFD := -1\n\tfor fd, d := range current {\n\t\tif !writable(d.flags) {\n\t\t\tcontinue\n\t\t}\n\t\tif _, old := baseline[fd]; old {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tif d.identity == c.identity {\n\t\t\tif d.flags&unix.O_ACCMODE != unix.O_RDWR || d.links != 1 || mainFD != -1 {\n\t\t\t\treturn nil, ErrRefused\n\t\t\t}\n\t\t\tmainFD = fd\n\t\t}\n\t}\n\tif mainFD < 0 {\n\t\treturn nil, ErrRefused\n\t}\n\tbound := &boundConnection{Conn: native, owner: c, mainFD: mainFD, siblings: map[string]fileIdentity{}}\n\tif e = bound.check(); e != nil {\n\t\treturn nil, e\n\t}\n\tquery, ok := native.(driver.QueryerContext)\n\tif !ok {\n\t\treturn nil, ErrRefused\n\t}\n\trows, e := query.QueryContext(ctx, \"PRAGMA database_list\", nil)\n\tif e != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tvalues := make([]driver.Value, 3)\n\tif rows.Next(values) != nil || values[1] != \"main\" || values[2] != c.path {\n\t\trows.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tif e = rows.Next(values); e != io.EOF {\n\t\trows.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tif rows.Close() != nil {\n\t\treturn nil, ErrUnavailable\n\t}"
+ },
+ {
+ "id": "S14",
+ "file": "internal/operator/engine.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/engine.go",
+ "sha256": "76b234222e95df223158aac4fe34b0ab954e75892a0c86f088bcc7c0a9d6d125",
+ "line": 68,
+ "end_line": 137,
+ "excerpt": "func (e *Engine) Execute(ctx context.Context, raw []byte, mutate Mutation) ([]byte, error) {\n\tif e == nil || mutate == nil {\n\t\treturn nil, ErrRefused\n\t}\n\treq, err := e.verifier.Verify(raw)\n\tif err != nil {\n\t\treturn nil, ErrRefused\n\t}\n\ta := req.authorization\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\tconn, err := e.db.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer conn.Close()\n\tfor _, statement := range []string{\"PRAGMA foreign_keys=ON\", \"PRAGMA secure_delete=ON\", \"PRAGMA busy_timeout=1000\"} {\n\t\tif _, err = conn.ExecContext(ctx, statement); err != nil {\n\t\t\treturn nil, ErrUnavailable\n\t\t}\n\t}\n\tvar fk, secure int\n\tvar journal string\n\tif conn.QueryRowContext(ctx, \"PRAGMA foreign_keys\").Scan(&fk) != nil || fk != 1 || conn.QueryRowContext(ctx, \"PRAGMA secure_delete\").Scan(&secure) != nil || secure != 1 || conn.QueryRowContext(ctx, \"PRAGMA journal_mode\").Scan(&journal) != nil || journal != \"wal\" {\n\t\treturn nil, ErrUnavailable\n\t}\n\tviolations, err := conn.QueryContext(ctx, \"PRAGMA foreign_key_check\")\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tbad := violations.Next()\n\treadErr := violations.Err()\n\tcloseErr := violations.Close()\n\tif bad || readErr != nil || closeErr != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = conn.ExecContext(ctx, \"BEGIN IMMEDIATE\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tfinished := false\n\tdefer func() {\n\t\tif !finished {\n\t\t\tcleanup, cancel := context.WithTimeout(context.Background(), time.Second)\n\t\t\tdefer cancel()\n\t\t\tif _, err := conn.ExecContext(cleanup, \"ROLLBACK\"); err != nil {\n\t\t\t\t_ = conn.Raw(func(any) error { return driver.ErrBadConn })\n\t\t\t}\n\t\t}\n\t}()\n\tvar storedOrigin, storedInstallation, storedRegistry, storedDevice, storedHead, storedKey string\n\tvar storedSequence, storedCompleted int64\n\tstateErr := conn.QueryRowContext(ctx, \"SELECT origin,installation,registry,device,sequence,head,completed_at,key_id FROM \"+e.prefix+\"_state WHERE singleton=1\").Scan(&storedOrigin, &storedInstallation, &storedRegistry, &storedDevice, &storedSequence, &storedHead, &storedCompleted, &storedKey)\n\tif stateErr != nil && !errors.Is(stateErr, sql.ErrNoRows) {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif stateErr == nil && (storedOrigin != a.Origin || storedInstallation != a.Installation || storedRegistry != a.Registry || storedDevice != a.Device || storedKey != e.verifier.kid || storedSequence <= 0 || !CanonicalToken(storedHead) || storedCompleted <= 0 || e.now().Unix() < storedCompleted) {\n\t\treturn nil, ErrRefused\n\t}\n\tvar oldAction, oldHead, oldOperator string\n\tvar oldSequence int64\n\tvar oldMAC, sealed []byte\n\terr = conn.QueryRowContext(ctx, \"SELECT action,sequence,authorization_head,request_mac,sealed_result,operator_ref FROM \"+e.prefix+\"_results WHERE operation_id=?\", a.OperationID).Scan(&oldAction, &oldSequence, &oldHead, &oldMAC, &sealed, &oldOperator)\n\tif err == nil {\n\t\tif stateErr != nil || storedSequence < a.Sequence || oldOperator != a.Device || oldAction != a.Action || oldSequence != a.Sequence || oldHead != req.head || !hmac.Equal(oldMAC, e.mac(req)) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tresult, openErr := e.sealer.Open(e.purpose(a), sealed)\n\t\tif openErr != nil || len(result) == 0 || len(result) > InputLimit {\n\t\t\treturn nil, ErrUnavailable\n\t\t}"
+ },
+ {
+ "id": "S15",
+ "file": "internal/operator/verification.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/verification.go",
+ "sha256": "547fef12d2ccdab9a41a172677c0be37d8f1d04b0ada9bd9b15b5a3d7e332c71",
+ "line": 27,
+ "end_line": 51,
+ "excerpt": "type ActivationEvidence struct {\n\tVersion int `json:\"version\"`\n\tPolicy string `json:\"policy\"`\n\tAttempt string `json:\"attempt_id\"`\n\tConsumer string `json:\"consumer\"`\n\tTeamSQID string `json:\"team_sqid\"`\n\tApp string `json:\"app\"`\n\tAudience string `json:\"audience\"`\n\tGeneration string `json:\"generation\"`\n\tRecordSequence int64 `json:\"record_sequence\"`\n\tRecordDigest string `json:\"record_digest\"`\n\tEpoch int64 `json:\"epoch\"`\n\tOwner string `json:\"owner_ref\"`\n\tAppVersion string `json:\"app_version\"`\n\tArtifactDigest string `json:\"artifact_digest\"`\n\tEnvironmentBinding string `json:\"environment_binding\"`\n\tManifestDigest string `json:\"credential_manifest_digest\"`\n\tAliasHost string `json:\"alias_host\"`\n\tStarted int64 `json:\"started_at\"`\n\tCompleted int64 `json:\"completed_at\"`\n}\ntype ActivationInput struct {\n\tInputBase\n\tEvidence ActivationEvidence `json:\"evidence\"`\n}"
+ },
+ {
+ "id": "S16",
+ "file": "internal/operator/verification.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/verification.go",
+ "sha256": "547fef12d2ccdab9a41a172677c0be37d8f1d04b0ada9bd9b15b5a3d7e332c71",
+ "line": 182,
+ "end_line": 184,
+ "excerpt": "\tif e != nil || p.Version != 1 || p.Policy != \"oficina/team-activation/v1\" || !CanonicalToken(p.Attempt) || !version(p.AppVersion) || !CanonicalToken(p.ArtifactDigest) || !CanonicalToken(p.EnvironmentBinding) || !CanonicalToken(p.ManifestDigest) || p.AliasHost != u.Host || p.Started <= 0 || p.Completed < p.Started || p.Completed > now || now-p.Completed >= 300 {\n\t\treturn nil, ErrRefused\n\t}"
+ },
+ {
+ "id": "S17",
+ "file": "internal/provisioner/prepare_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/provisioner/prepare_linux.go",
+ "sha256": "4b04bb15b1d22bc825207548b0bb8d84266a4c03dc84af125ed91f260320f89e",
+ "line": 77,
+ "end_line": 141,
+ "excerpt": "func decodeOperationPlan(raw []byte) (OperationPlan, any, error) {\n\tvar p OperationPlan\n\tif len(raw) == 0 || len(raw) > operator.BodyLimit || json.Unmarshal(raw, &p, json.RejectUnknownMembers(true)) != nil || p.Version != 1 || !operator.CanonicalToken(p.Installation) || !operator.CanonicalToken(p.Operation) || len(p.Input) == 0 || len(p.Input) > operator.InputLimit {\n\t\treturn p, nil, ErrRefused\n\t}\n\tvar input any\n\tvar base *operator.InputBase\n\tswitch p.Action {\n\tcase \"directory.initialize\":\n\t\tin := new(operator.InitializeInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"credential.owner-seed\":\n\t\tin := new(operator.OwnerInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"directory.seed-team\":\n\t\tin := new(operator.SeedInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"directory.provision-consumer\":\n\t\tin := new(operator.ProvisionInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tdefault:\n\t\t// Verification and activation await checked record/evidence collectors.\n\t\treturn p, nil, ErrRefused\n\t}\n\trole := \"directory\"\n\tif p.Action == \"credential.owner-seed\" {\n\t\trole = \"credential\"\n\t}\n\tif p.Role != role || json.Unmarshal(p.Input, input, json.RejectUnknownMembers(true)) != nil || base.Version != 1 || base.Operation != p.Action || base.OperationID != p.Operation {\n\t\treturn p, nil, ErrRefused\n\t}\n\treturn p, input, nil\n}\nfunc preparationScope(s *installationState, input any) bool {\n\tif s == nil {\n\t\treturn false\n\t}\n\tswitch in := input.(type) {\n\tcase *operator.InitializeInput:\n\t\treturn in.ExpectedGeneration == nil && operator.CanonicalToken(in.Generation) && in.Baseline == \"operator-attests-never-provisioned\"\n\tcase *operator.OwnerInput:\n\t\tsqid, e := operator.TeamSQID(in.TeamID)\n\t\taddress, parseErr := mail.ParseAddress(in.Address)\n\t\treturn e == nil && parseErr == nil && address.Address == in.Address && address.Name == \"\" && in.ExistingOnly && in.TeamSQID == sqid && in.Directory == s.Plan.Directory.Origin && len(in.Address) > 0 && len(in.Address) <= 320\n\tcase *operator.SeedInput:\n\t\treturn in.Generation == s.Generation && s.Generation != \"\"\n\tcase *operator.ProvisionInput:\n\t\treturn in.Generation == s.Generation && s.Generation != \"\"\n\t}\n\treturn false\n}\nfunc prepareRequest(ctx context.Context, statePath, floorPath string, password, plan []byte, output *requestOutput) (PreparationInfo, error) {\n\tp, input, e := decodeOperationPlan(plan)\n\tif e != nil || output == nil {\n\t\treturn PreparationInfo{}, ErrRefused\n\t}\n\tj, e := existingJournal(statePath, floorPath, password)\n\tif e != nil {\n\t\treturn PreparationInfo{}, e\n\t}\n\tdefer closeExisting(j)"
+ },
+ {
+ "id": "S18",
+ "file": "cmd/home/main.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/cmd/home/main.go",
+ "sha256": "a414edf4e33e2be0293aeec50e5973bff7ad8978f0188b1c589547ab56522701",
+ "line": 52,
+ "end_line": 119,
+ "excerpt": "func main() {\n\tlogger := slog.Default()\n\n\t// DBPath is set here, not required as a flag \u2014 see the package\n\t// comment. Relative, so Resolve joins it to $STATE_DIRECTORY.\n\topts, err := rastrillo.Resolve(rastrillo.Options{Logger: logger, DBPath: \"home.db\"})\n\tif err != nil {\n\t\tlogger.Error(\"resolve\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// Every secret and setting whose absence is silent is validated\n\t// before anything serves. Each refusal here is a case where\n\t// continuing would produce an app that answers /healthz perfectly\n\t// well and is broken or leaking: no DEK and addresses persist in the\n\t// clear, no pepper and every person row is orphaned, no SMTP host\n\t// and magic links are written to platform-held logs instead of\n\t// emailed. The database path cannot be empty on this path \u2014 it is\n\t// set below \u2014 but LoadSecrets checks it anyway, for the caller that\n\t// builds its own Options.\n\truntime, err := home.LoadRuntime(opts.DBPath, logger)\n\tif err != nil {\n\t\tlogger.Error(\"config\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// Before db.Open, never after: Open calls Ping, which opens the\n\t// writer pool's single long-lived connection there and then, and a\n\t// hook registered afterwards misses it forever. That connection is\n\t// the only one that performs DELETEs.\n\thome.RegisterSecureDelete()\n\n\td, err := rdb.Open(opts.DBPath, logger)\n\tif err != nil {\n\t\tlogger.Error(\"open db\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer d.Close()\n\n\t// Ledgered, once at boot, forward-only. A boot that cannot reconcile\n\t// its schema refuses rather than guessing, same as a failed open.\n\tif _, err := migrate.Apply(context.Background(), d, runtime.Schema()); err != nil {\n\t\tlogger.Error(\"migrate\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\tapp, err := home.NewRuntime(runtime, d, logger)\n\tif err != nil {\n\t\tlogger.Error(\"wire app\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// rastrillo.Options.Mux wants a *http.ServeMux; the app's own\n\t// router is a chi.Router (an http.Handler), so it mounts under one.\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", app.Router())\n\topts.Mux = mux\n\topts.CSP = app.SecurityPolicy()\n\n\t// Blanked because this file opened the handle itself: Serve would\n\t// otherwise open a second one against the same file.\n\topts.DBPath = \"\"\n\n\tif err := rastrillo.Serve(opts); err != nil {\n\t\tlogger.Error(\"serve\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n}"
+ },
+ {
+ "id": "P1",
+ "absolute_path": "/home/paulca/amadan.net/carlos/platform/.claude/worktrees/overnight-always-awake-design/implementation/maintenance-exec.md",
+ "line": 55,
+ "end_line": 57,
+ "excerpt": "Resume is a separately approved operation, not `clear maintenance`. It names an expected serving release/artifact, configuration/key binding and successful app-specific compatibility-check command from that release. Platform verifies all pins under the fence/lease, runs the non-serving checker against the existing DB, verifies integrity/checkpoint and records its result. The app checker owns format/key/authorization compatibility; platform cannot infer it from exit of an earlier migration or a byte-compatible old binary. Docs TeamMode's minimum authorization-aware release floor is one such consumer requirement.\n\nOnly after the checker succeeds may the worker publish resume-ready evidence, install the pinned serving release/config and arrange the lease-to-serving replication handoff. Clear the fence through one guarded transition bound to this evidence; old/new worker races cannot resurrect a superseded resume. Admit HTTP only after the exact new process and replication are healthy and report the approved version; retain a durable resumed receipt. If process startup/replication/version verification fails, return to fenced/failed, not ready. The implementation must decide and test the precise lease handoff before code approval; simply releasing and hoping the next wake uses the approved pins is insufficient.",
+ "sha256": "82912e12d845b42179507362951a7b17ccf04632b9c59537e0f6b78246152335"
+ }
+ ]
+}
diff --git a/implementation/compatibility-checker/probe/observation.json b/implementation/compatibility-checker/probe/observation.json
new file mode 100644
index 0000000..7a1c2ac
--- /dev/null
+++ b/implementation/compatibility-checker/probe/observation.json
@@ -0,0 +1,28 @@
+{
+ "source_revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "test": "TestCheckerReadOnlyObservation",
+ "exit_code": 0,
+ "scope": "observational synthetic hot-WAL existing DB, exact current pinned connector; not a checker implementation or complete acceptance proof",
+ "procedure": [
+ "Separate child seeds WAL-mode table with one row; os.Exit without DB.Close preserves hot WAL",
+ "Parent hashes main/WAL/SHM only while no checker process is active",
+ "Separate reader child uses newBoundDatabase, PRAGMA query_only=ON, SELECT count(*)=1, checked close",
+ "Parent rehashes files after reader exits"
+ ],
+ "observations": {
+ "before": {
+ "main": "52a371445ce0812ca930aea418e7d7e9d6459f1778a6e14cb56592f08f5a08af",
+ "shm": "829996e6b81530e87ffc28a9ec48e135216cc8f45c31d7c256f36f21e90145a9",
+ "wal": "6a9d5e24139ca28e2b5993f55a61e0f99aaab4ab9471984184b5e045138bfadf"
+ },
+ "after": {
+ "main": "00e7703e9f60902de2294bf86a1ef2037b6999762ec647b4c24b2edefa39ad7b",
+ "shm": "absent",
+ "wal": "absent"
+ }
+ },
+ "conclusion": "Current mode=rw pinned connector plus query_only does not promise byte-level no mutation; checked readonly connector requires separate design/implementation proof.",
+ "repository_changed": false,
+ "live_calls": false,
+ "probe_sha256": "011b929f2990d7651b43e0e14a57f28330d0c5a616322307f5987685847da57d"
+}
diff --git a/implementation/compatibility-checker/probe/readonly_probe_test.go.txt b/implementation/compatibility-checker/probe/readonly_probe_test.go.txt
new file mode 100644
index 0000000..d9f056f
--- /dev/null
+++ b/implementation/compatibility-checker/probe/readonly_probe_test.go.txt
@@ -0,0 +1,54 @@
+//go:build linux
+package operator
+
+import (
+ "context"
+ "crypto/sha256"
+ "database/sql"
+ "encoding/hex"
+ "encoding/json"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+ "time"
+ "golang.org/x/sys/unix"
+)
+
+func TestCheckerReadOnlyObservation(t *testing.T) {
+ path := os.Getenv("OFICINA_CHECKER_PROBE_PATH")
+ mode := os.Getenv("OFICINA_CHECKER_PROBE_MODE")
+ if mode == "seed-hot" {
+ db, err := sql.Open("sqlite", "file:"+path); if err != nil { t.Fatal(err) }
+ if _,err = db.Exec("PRAGMA journal_mode=WAL; PRAGMA wal_autocheckpoint=0; CREATE TABLE changes(value INTEGER); INSERT INTO changes VALUES(42)"); err != nil { t.Fatal(err) }
+ os.Exit(0)
+ }
+ if mode == "read" {
+ var st unix.Stat_t
+ if err := unix.Stat(path,&st); err != nil { t.Fatal(err) }
+ b,err:=newBoundDatabase(path,uint64(st.Dev),st.Ino,time.Now().Add(time.Minute)); if err != nil { t.Fatal(err) }
+ ctx:=context.Background()
+ if _,err=b.db.ExecContext(ctx,"PRAGMA query_only=ON");err!=nil {t.Fatal(err)}
+ var count int
+ if err=b.db.QueryRowContext(ctx,"SELECT count(*) FROM changes").Scan(&count);err!=nil {t.Fatal(err)}
+ if count!=1 {t.Fatal("wrong count",count)}
+ if err=b.close();err!=nil {t.Fatal(err)}
+ return
+ }
+ snapshot:=func(path string) map[string]string {
+ out:=map[string]string{}
+ for _,suffix:=range []string{"","-wal","-shm"} {
+ raw,err:=os.ReadFile(path+suffix)
+ if os.IsNotExist(err) {out[suffix]="absent";continue}; if err!=nil {t.Fatal(err)}
+ sum:=sha256.Sum256(raw);out[suffix]=hex.EncodeToString(sum[:])
+ };return out
+ }
+ path=filepath.Join(t.TempDir(),"home.db")
+ for _,childMode:=range []string{"seed-hot","read"} {
+ if childMode=="read" {raw,_:=json.Marshal(snapshot(path));t.Log("before",string(raw))}
+ cmd:=exec.Command(os.Args[0],"-test.run=^TestCheckerReadOnlyObservation$","-test.v")
+ cmd.Env=append(os.Environ(),"OFICINA_CHECKER_PROBE_MODE="+childMode,"OFICINA_CHECKER_PROBE_PATH="+path)
+ if raw,err:=cmd.CombinedOutput();err!=nil {t.Fatalf("%s: %v: %s",childMode,err,raw)}
+ }
+ raw,_:=json.Marshal(snapshot(path));t.Log("after",string(raw))
+}
diff --git a/implementation/compatibility-checker/probe/reproduction.json b/implementation/compatibility-checker/probe/reproduction.json
new file mode 100644
index 0000000..1a612f5
--- /dev/null
+++ b/implementation/compatibility-checker/probe/reproduction.json
@@ -0,0 +1,18 @@
+{
+ "kind": "test-only Go overlay probe",
+ "home_base_revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "source": "readonly_probe_test.go.txt",
+ "overlay_virtual_file": "internal/operator/readonly_probe_test.go",
+ "overlay_instruction": "Use absolute paths in a Go overlay Replace mapping from the virtual file in a Home7e checkout to this saved .go.txt source. Run only TestCheckerReadOnlyObservation in internal/operator with that overlay; do not install it as an implementation package. Use a real disk scratch TMPDIR without symlink ancestors.",
+ "command_argv": [
+ "go",
+ "test",
+ "-overlay=<absolute overlay.json>",
+ "./internal/operator",
+ "-run",
+ "^TestCheckerReadOnlyObservation$",
+ "-count=1",
+ "-v"
+ ],
+ "expected_observation": "One synthetic hot-WAL database. Before main/WAL/SHM exist; after read/close main bytes differ and sidecars are absent. PASS is an observation, not satisfaction of the readonly requirement."
+}
diff --git a/implementation/compatibility-checker/proposal.json b/implementation/compatibility-checker/proposal.json
new file mode 100644
index 0000000..e5e5300
--- /dev/null
+++ b/implementation/compatibility-checker/proposal.json
@@ -0,0 +1,386 @@
+{
+ "version": 1,
+ "status": "UNAPPROVED DESIGN PROPOSAL; no runtime implementation or authority conferred",
+ "home_revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "audit": "audit.json",
+ "audit_sha256": "0625d33bb795c1cf415e1e213d8e572e65f8ae4ebcf71ab52adf264c076e8b60",
+ "objective": "One fixed non-serving Home compatibility command from the selected serving release, proving configuration and existing-database compatibility before maintenance resume. An unmounted facts collector is not delivery.",
+ "scope": {
+ "roles": [
+ "credential",
+ "directory"
+ ],
+ "legacy_role": "Refuse empty/legacy HOME_ROLE; migration of legacy deployment to split role requires its own explicit expected-state plan.",
+ "execution": "Fixed proposed command home compatibility-check-v1, dispatched before rastrillo.Resolve/LoadSecrets/db.Open/migrate.Apply/NewRuntime. Name is proposed, not a currently supported command.",
+ "no_new_authority": "No signer, trust-on-first-use, owner gesture bypass, new mutation verb or custom maintenance token. Use the separately reviewed platform launch verifier and private transport; unavailable verifier means command unavailable."
+ },
+ "config": {
+ "input": "One immutable protected environment snapshot supplied by verified launch. Shared pure parsing is extracted from LoadOrigins/LoadRuntime/loadRosterRuntime/key32/exchangeJSON; serving loader reuses it. No mailer/server construction or process-global env mutation by checker.",
+ "required": "All serving-required role configuration, including syntax/presence of mail configuration for credential, is validated without creating a sender or testing connectivity. Readiness of SMTP/network is outside this no-network check.",
+ "origins": "Exact credential, directory and instance origins, role and expected origin must match trusted expected bindings byte-for-byte after existing validation; do not normalize one into another.",
+ "manifest": {
+ "credential": "Parse HOME_CONSUMERS or its exclusive encoded alternative with current bounds and rules. Use validated map; reject duplicate JSON member names as serving parser does. Sort entries by unsigned UTF-8 byte order of consumer ID. Canonical bytes are standard Go encoding/json.Marshal of []any{\"oficina/home/consumer-manifest/v1\", [][2]string{{id,origin},...}} with default escaping and no trailing newline. This deliberately defines an array representation, not arbitrary object serialization. All strings are exact validated values; no case-folding, slash trimming or Unicode normalization.",
+ "digest": "SHA256(canonical bytes), encoded base64.RawURLEncoding, exactly43 chars. This matches ActivationEvidence.ManifestDigest shape; lowercase-hex key IDs are not used for this field.",
+ "directory": "Manifest digest is absent/null, never hash of an invented empty manifest. Directory runtime does not load credential HOME_CONSUMERS. The provisioner obtains the credential observation separately.",
+ "vectors": "Tests freeze empty encoding for algorithm-only vector (empty runtime map still refuses), one entry, reordered input, whitespace/base64 equivalence, changed origin, forbidden duplicate member and bound overflow.",
+ "approval": "New canonical-byte convention; requires review before producer/comparator usage."
+ }
+ },
+ "public_key_facts": {
+ "format": "Role-labelled sorted arrays of {fingerprint,uses}; fingerprint is lowercase hex SHA256 of exact decoded canonical P256 SignPub bytes, matching operator.keyID/rosterKeyID. Sort by fingerprint, reject duplicate entries rather than erase configuration mistakes. Uses are explicit active-sign and/or accepted-verify; active signer cannot be inferred from a verifier set.",
+ "credential": {
+ "command_authorizer": "Accepted operator.Verifier key (one); no private key is expected on Home.",
+ "owner_seed": "Active Credential.signer key (one).",
+ "browser_assertion": "Active Runtime.signer key and accepted verifier set used by this runtime (current implementation one derived active key); do not report unconfigured historical keys.",
+ "directory_provisioning": "Absent.",
+ "roster": "Absent; current runtime rejects roster config on credential."
+ },
+ "directory": {
+ "command_authorizer": "Accepted operator.Verifier key (one).",
+ "owner_seed": "Accepted OwnerVerifier key (one).",
+ "directory_provisioning": "Active Directory.signer key (one).",
+ "browser_assertion": "Exact Runtime.keys accepted set, current bound1..8; no active private signer.",
+ "roster": "Directory.keys exact accepted roster key set (1..8) plus runtime active roster signer only when mode=serve. Disabled means no active signer, not missing accepted provisioning pins."
+ },
+ "separation": "Preserve all NewCredential/NewDirectory checks. Command-authorizer, owner-seed, directory provisioning, browser assertion and roster role key bytes must be pairwise distinct across roles. Same roster key may be both active-sign and accepted-verify in that one role. Directory runtime active roster signer must appear in Directory.keys with same fingerprint and configured ID; credential active assertion must appear in its accepted set. These cross-runtime consistency checks are proposed additions needed for truthful complete facts.",
+ "key_id": "Report configured verification key IDs separately only if required by private result comparator; compare exact ID+bytes in expected config even when facts use fingerprint. Key IDs are not proof of public bytes.",
+ "source_of_operator_configuration": "Typed configuration shared with actual fixed operator adapter. Current code has constructors but no runtime loader for these pins; do not invent environment variables in collector. Command remains unavailable until the operator adapter and checker consume the same reviewed role configuration.",
+ "bounds": "At most8 keys per set, six fixed role labels, no arbitrary role names; result bound below still applies."
+ },
+ "trusted_expectations": {
+ "authority": "Expected values must be enrolled before this checker from the authenticated protected platform configuration/approved installation baseline and bound to this immutable resume attempt. Copying the current snapshot into expected values inside the checker proves nothing and is forbidden. No unsigned request-supplied expected fingerprint is trusted.",
+ "fingerprints": "Preserve existing InstallationTarget.DataKey lowerhex SHA256 of decoded32-byte DEK convention only once its enrollment derivation is explicitly confirmed. Propose the same decoded-byte SHA256 lowerhex for pepper, signin key and operator request-MAC key; role-labelled fields, never hash encoded env text. These extra expectations are new explicit enrollment fields, not currently supplied by InstallationTarget.",
+ "matrix": [
+ {
+ "key": "HOME_DEK",
+ "credential_database_proof": "Authenticate every existing signin_links.sealed_address with signin.address and every credential operator sealed result with operator.result/v1/<origin>/<operation>/<action>. Discard plaintext immediately; no echo or persistence. This proves those stored ciphertexts, not key history when none remain.",
+ "directory_database_proof": "Authenticate every teams.sealed_name with directory.team-name/<id> and every directory operator sealed result using existing purpose; validate resulting format with existing pure validators.",
+ "required_even_if_ciphertexts_exist": "Exact trusted enrolled fingerprint equality. Missing ciphertexts do not allow omission. No newly sealed self-test blob counts as compatibility evidence."
+ },
+ {
+ "key": "HOME_PEPPER",
+ "roles": [
+ "credential"
+ ],
+ "database_proof": "None from blind_index alone: no readable address exists to recompute expected HMAC. Do not add addresses, request user email, guess addresses or treat index shape as proof.",
+ "required": "Trusted enrolled fingerprint equality; absent expectation refuses."
+ },
+ {
+ "key": "HOME_SIGNIN_KEY",
+ "roles": [
+ "credential"
+ ],
+ "database_proof": "No reliable persistent witness: pending keymail blob belongs to browser flow; stored session success does not prove this key.",
+ "required": "Trusted enrolled fingerprint equality; no minted session or synthetic self-encryption proof."
+ },
+ {
+ "key": "operator request-MAC key",
+ "roles": [
+ "credential",
+ "directory"
+ ],
+ "database_proof": "Stored request_mac without original private input cannot establish key identity.",
+ "required": "Trusted enrolled fingerprint equality; no request replay or sequence writes."
+ }
+ ],
+ "not_claimed": "Fingerprint comparison proves continuity with enrollment, not that enrollment was correct. Ciphertext checks prove present data compatibility only. Signing key validation proves current configured keypair math and expected public binding, not independent key-custody attestation."
+ },
+ "database_acceptance": {
+ "common": "Exact existing regular database identity from verified launch; exact role-specific schema and trusted instance enrollment. Never create missing file or invoke general migrator. Check sqlite integrity_check result exactly ok and foreign_key_check empty within deadline. Refuse unknown extra/missing/modified schema, corrupt rows or contradictory binding.",
+ "credential_set": "migrate.Merge(home.BootSchema, operator.CredentialSchema) from selected release. At7e BootSchema = sessions.Schema + passkey.Schema + home.Schema; CredentialSchema namespace oficina_credential_operator with0001_operator and0002_operator_key_identity.",
+ "directory_set": "migrate.Merge(directorySchema, directorydata.OperatorSchema, operator.DirectorySchema) from selected release. directorySchema = sessions.Schema + oficina_handoff migrations + directorydata.Schema + directorydata.RosterSchema. Operator bindings namespace oficina_directory_operator_bindings; DirectorySchema namespace oficina_directory_operator with0001_operator,0002_owner_receipts,0003_operator_key_identity.",
+ "current_gap": "Runtime.Schema currently omits operator.CredentialSchema/operator.DirectorySchema and directorydata.OperatorSchema. Checker never fixes that. Separately reviewed additive deployment must install required sets before the checker can succeed.",
+ "ledger": "Use Set.All plus migrate.Checksum of exact embedded SQL. Read rastrillo_migrations through pinned connection; every expected ID and checksum must match and no extra ID is accepted. Go migrations, if introduced, require explicit release profile rather than empty-checksum inference. Never call Apply.",
+ "structure": "Build expected normalized sqlite_schema/table/index/FK/trigger/view shape at build/test time by replaying exact reviewed migration sets into a scratch DB; freeze expected descriptor in release. Compare actual structure read-only, including constraints/index expressions/triggers/views; migrate.Read alone lacks complete CHECK/FK/trigger semantics and is insufficient. Normalize only SQLite-stable metadata/formatting defined by fixture generation, not SQL semantics through regex. Generated internal sqlite tables and ledger are explicitly included or excluded by fixed rule. Exact expected sqlite_schema SQL from the same migration execution is acceptable conservative first profile; harmless divergent DDL may refuse.",
+ "credential_identity": "No directory/team/roster namespace; people refs and blind indexes retain their current shape. If operator_state exists, exact origin/installation/registry/device/key identity must match trusted enrollment and sequence/head/completion must match approved expected state constraints. Do not infer app identity from table names alone.",
+ "directory_identity": "No people/signin/passkey credential namespace; exact operator origin/installation/registry/device/key identity when initialized; generation and existing owner/team memberships agree with trusted baseline expectations. Validate team sqid/label, purpose-bound name, bounded epochs, and existing registry/provisioning references using current pure validators. No new generation, team or owner creation.",
+ "empty_policy": "No default empty DB success. Missing file, empty schema, missing ledger or untrusted role binding always refuse. A schema-complete but authority-empty initial role is accepted ONLY with a separately enrolled explicit baseline profile binding exact DB identity, role/origins, required schema, expected absence of operator state/generation/teams/people and key fingerprints. This permits planned first initialization without inventing ownership, but that baseline profile must be reviewed/enrolled; a caller boolean or just current count=0 is insufficient. Initialized profile requires exact expected state presence and at least its enrolled durable identity witnesses; zero rows unexpectedly refuses.",
+ "bounded_scan": "Single read transaction over all compatibility-relevant rows; proposed deadline min(launch deadline,30seconds), at most100000 rows and64MiB authenticated ciphertext cumulatively, per-value bounds from schema. Exceeding limits returns unavailable, never success from sampling. Do not allocate plaintext corpus; scan/discard one value at a time. Larger deployments need separately reviewed limits.",
+ "concurrent_state": "No serving/replication writer is allowed during checker under platform fence/retained lease. Read snapshot is not a substitute for that ownership proof."
+ },
+ "database_opening": {
+ "decision": "Require a reviewed read-only variant of existing actual-descriptor connector, not current newBoundDatabase and not a bare sql.Open(mode=ro).",
+ "identity": "Retain nofollow ancestor walk, single hardlink/device/inode pins, actual driver-open descriptor inventory and checks during all queries/rows/close. Adapt expected main descriptor to O_RDONLY; pin any main/WAL/SHM identities before and after actual open. No fallback to mode=rw or path-only proof; no immutable=1 because it suppresses change/WAL handling assumptions.",
+ "os_boundary": "Run selected command with DB directory/files read-only in its reviewed process namespace and prohibit arbitrary writable regular inherited descriptors. Private result is anonymous pipe. Sandbox setup belongs to reviewed launch integration; merely setting PRAGMA query_only is insufficient.",
+ "wal_shm": "Main and WAL bytes/presence/identity must not change; SHM bytes/presence/identity must also remain unchanged by checker. Locks/descriptor offsets may change but are not stored data. Open coherent pre-existing sidecars read-only if SQLite supports the actual state; missing sidecars or recovery requiring writes must refuse. No checkpoint, SHM rebuild, journal mode change, deletion or creation in checker. Platform may perform its separately authorized checked checkpoint before invocation, then rebind the observed files; checker cannot request implicit repair.",
+ "actual_driver_gate": "This is a proposed dependency, not a proven capability of pinned modernc. Prove readonly hot-WAL and checkpointed WAL-mode cases on exact driver/kernel; if coherent readonly open cannot meet constraints, refuse and return design for review rather than silently allow housekeeping writes.",
+ "root_probe": "probe/readonly_probe_test.go and overlay.json show current connector + query_only + SELECT can change main SHA and remove WAL/SHM at close. Observational test passes; it proves current helper is unsuitable, not checker safety.",
+ "postcondition": "Close must complete successfully and pinned identity/no-change checks must pass before success result is released. Output assembled privately but withheld until all DB handles are closed and final evidence checked."
+ },
+ "launch_and_result": {
+ "required_input_binding": "Verified platform launch pins request/attempt/guard generation, account/app/primary host, selected immutable executable digest, immutable config snapshot binding, existing DB device/inode, role/origin and enrolled expected-state digest. Exact fields/API come from reviewed launch contract; application cannot self-authorize or accept raw env equivalents.",
+ "freshness": "One process invocation per platform-approved checker attempt, deadline enforced throughout parsing/open/scans/close/output. Invocation does not mutate any replay ledger; platform owns attempt freshness and accepts only result from the exact captured child pipe under retained fence/lease.",
+ "result": "Proposed bounded private JSON version1/purpose oficina/home/compatibility/v1, role, exact origins, role-labelled public fingerprints, credential manifest digest or null, schema-profile digest, verified expected-state digest, and binding identifiers copied only from verified launch. Success contains no subjects, labels, addresses, ciphertext, private keys, secret fingerprints, tokens or SQL. Secret fingerprint comparison yields only overall success. This is plain captured private result, not a new signed Home output protocol.",
+ "limits": "Maximum16KiB success result. Failure writes no partial success JSON and uses generic nonzero exit; no config values, DB row values or driver SQL/error strings in stderr/logs. Platform capture limit remains authoritative if lower.",
+ "consumer": "Platform verifies exact attempt/artifact/config/DB/result binding before resume-ready; provisioner compares facts to its enrolled expected evidence. Receipt or earlier checker result cannot satisfy a later resume. Source build identity comes from verified selected artifact, not an untrusted self-reported version."
+ },
+ "implementation_slices": [
+ {
+ "order": 1,
+ "work": "Review this full contract and settle opening/launch/enrollment dependencies; establish typed expected input/output and complete command acceptance tests first."
+ },
+ {
+ "order": 2,
+ "work": "Implement shared pure role config parsing and exact facts/digest as part of checker branch, preserving serving parser parity. No independent claim of checker completion."
+ },
+ {
+ "order": 3,
+ "work": "Implement/review read-only actual-descriptor connector and complete DB compatibility checks with before/after byte evidence; no migration/authority side effects."
+ },
+ {
+ "order": 4,
+ "work": "Mount fixed early command only through reviewed launch verifier and private pipe; whole command tests + full Home privacy/native/race/CI + explicit Fable code review. No live activation inferred."
+ }
+ ],
+ "acceptance": [
+ "Parser parity with actual serving configuration including credential/directory/legacy, encoded platform values, disabled roster and unset-versus-empty settings.",
+ "Digest determinism and exact downstream raw-base64url shape; ordering/whitespace changes follow reviewed semantics; changed origin changes digest.",
+ "All active/accepted public key roles accounted for; collisions, wrong role/pin, absent private config refuse; canaries prove no private bytes in result/errors/logs.",
+ "No listener, mail send, session mint, authority journal mutation, migration or DB creation; actual subprocess with denied network and controlled inherited descriptors.",
+ "Synthetic existing credential/directory DBs: correct role/schema/key passes; wrong role/origin/key, partial/future/corrupt ledger refuses; existing identities/owners/generation/sequence unchanged.",
+ "Actual DB/WAL/SHM before/after evidence matches reviewed no-write contract, including hot WAL, readonly permissions and failed checks.",
+ "Replacement-path/open-restore race, hardlinks, expired deadline and actual descriptor mismatch refuse using existing connector proof or explicitly reviewed extension.",
+ "Selected artifact/environment/attempt mismatch and stale checker output cannot resume; prior action success and HTTP health cannot bypass checker.",
+ "Mutations removing schema/key verification, role separation or digest comparison must fail meaningful tests.",
+ "Actual complete subprocess tests use selected executable and immutable config, not only helper injection; success waits for close and postcondition.",
+ "Seed wrong DEK with no ciphertext: enrolled fingerprint mismatch refuses; no empty-data fast success. Wrong pepper/signin/MAC fingerprints refuse even when all DB structural checks pass.",
+ "Explicit baseline-empty profile cannot be enabled by request boolean, current count or missing enrollment; initialized profile cannot downgrade to empty.",
+ "Mutations allowing missing operator migration, future ledger ID, extra trigger, wrong role set, sampled scan completion, mode=rw fallback or early output must be killed.",
+ "Actual root housekeeping probe becomes negative control: forbidden current connector fails readonly invariant, reviewed connector preserves main/WAL/SHM bytes and identities or refuses without modifications.",
+ "No changes to sessions, people, owners, memberships, generation, operator heads/results, secret files or config; private canaries absent from logs/results and raw files/WAL."
+ ],
+ "unresolved_review_dependencies": [
+ "Readonly actual-descriptor connector and process namespace support require separate focused implementation review and empirical proof; no query_only shortcut.",
+ "Protected launch and selected artifact verifier remains separately reviewed platform dependency, not supplied by Home7e.",
+ "Typed operator runtime configuration is not mounted in Home7e; checker and actual operator must share it, not collect imaginary pins.",
+ "Trusted enrollment currently has one DataKey fingerprint, not explicit pepper/signin/MAC expected fields or role-state baseline. Proposed additions need review and authenticated collection before use.",
+ "Manifest canonical bytes, role-labelled facts, schema profile generation, empty-baseline enrollment, scan limits and fixed private output are new proposed conventions awaiting review.",
+ "This draft does not authorize converting existing legacy Home roles, enrolling owners, changing live keys, applying schema or resuming any real instance."
+ ],
+ "source_evidence": [
+ {
+ "id": "S1",
+ "file": "implementation/home-provisioner.md",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/implementation/home-provisioner.md",
+ "sha256": "6fc38e7ee071f2c41446d6c254591ac6999e90eb043e02bb418f6f4747e4deb5",
+ "line": 256,
+ "end_line": 274,
+ "excerpt": "Use maintenance's immutable protected environment binding and a fixed non-serving\napplication compatibility checker against that snapshot. The Home checker reports\nonly exact origins, active public operator/assertion/roster key fingerprints and\nconsumer-manifest digest. The Docs checker reports exact TeamMode bindings, verified\nprovisioning record digest, generation and SHA256 of the canonical bearer already\npresent in protected config. These are bounded private results, never public logs.\nCheckers make no network calls, mint no sessions and change no DB/key/authority.\nThey require separate small implementation/review slices; no current API is claimed\nto supply these application-specific facts. Existing secret fingerprints are compared\nprivately to enrolled fingerprints, without copying existing private keys out. Dial only configured\ncanonical HTTPS hosts with normal certificate validation, no redirects unless the\nspecific sign-in probe validates every expected hop. Compare full expected version\nin body/header and current platform route/alias mapping. Store bounded response\ndigests, typed binding facts and timestamps in the encrypted signed journal; token,\nemail, assertion and unrelated response content are never retained in evidence.\n\n## Activation gate and pending roster integration\n\nAn activation authorization signs exact consumer/team/app/audience, generation,"
+ },
+ {
+ "id": "S2",
+ "file": "implementation/home-operator-seed.md",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/implementation/home-operator-seed.md",
+ "sha256": "e1d14379b8642e3ada7d355b0e834a3d06acb8f662a6a142e9d738af16ac856b",
+ "line": 247,
+ "end_line": 265,
+ "excerpt": "Open an existing regular database with creation disabled, through the pinned\nplatform path. Check application identity, expected role/origin, migration ledger\nand required additive schema versions before any action. Never call the general\nweb startup migrator to repair an unexpected DB from this command. The deployment\napplies reviewed role-specific additive migrations before operator execution.\n\nAcquire one dedicated database/sql connection. Set foreign_keys ON before beginning\nand read it back as 1 on that exact connection; pooled connections cannot substitute\nfor this check. Also require secure_delete ON, expected journal configuration,\nno foreign_key_check violations, and the verified transport fence/lease. Take an\nimmediate write transaction with a bounded lock timeout; all idempotency, generation,\nsequence, owner receipt and registry preconditions are rechecked inside it. Do not\nperform network work while holding the lock. Refuse wrong clocks, time rollback\nrelative to persisted operator completion time, exhausted counters or corrupt rows.\nWrite all related authority and audit rows together. Close/checkpoint through the\nsupported transport protocol before resume; an uncertain commit remains fenced\nuntil querying the same operation establishes its outcome.\n\nNo success path changes existing sessions, assertion keys, content encryption,"
+ },
+ {
+ "id": "S3",
+ "file": "internal/home/runtime.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/runtime.go",
+ "sha256": "04ad2e232f37b4027ba1900bf0ff75de805f91fd360af464be13ada8d83023ab",
+ "line": 38,
+ "end_line": 145,
+ "excerpt": "func LoadRuntime(dbPath string, logger *slog.Logger) (Runtime, error) {\n\tvar cfg Runtime\n\tvar err error\n\tcfg.origins, err = LoadOrigins()\n\tif err != nil {\n\t\treturn Runtime{}, err\n\t}\n\tcfg.role = os.Getenv(\"HOME_ROLE\")\n\tif cfg.role != \"directory\" {\n\t\tcfg.roster, err = loadRosterRuntime(cfg.role, nil)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t}\n\tswitch cfg.role {\n\tcase \"\":\n\t\tcfg.secrets, err = LoadSecrets(dbPath, logger)\n\t\treturn cfg, err\n\tcase \"credential\":\n\t\tcfg.secrets, err = LoadSecrets(dbPath, logger)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tencodedPrivate := os.Getenv(\"HOME_ASSERTION_KEY\")\n\t\tif len(encodedPrivate) > 4096 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\traw, err := base64.StdEncoding.DecodeString(encodedPrivate)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.signer, err = assertioncrypto.UnmarshalKeypair(raw)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tif cfg.signer.SignPriv.D.Sign() <= 0 || cfg.signer.SignPriv.D.Cmp(elliptic.P256().Params().N) >= 0 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tpub := cfg.signer.SignPub()\n\t\tsum := sha256.Sum256(pub)\n\t\tcfg.keyID = hex.EncodeToString(sum[:])\n\t\tcfg.keys = map[string][]byte{cfg.keyID: pub}\n\t\trawManifest, err := exchangeJSON(\"HOME_CONSUMERS\", 8192)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\t// Sixteen pilot origins keep the exact CSP manifest within ordinary header\n\t\t// limits. Production registration needs a separately reviewed scalable path.\n\t\tif len(rawManifest) > 8192 || json.Unmarshal([]byte(rawManifest), &cfg.consumers) != nil || len(cfg.consumers) == 0 || len(cfg.consumers) > 16 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tfor id, origin := range cfg.consumers {\n\t\t\tif !consumerName(id) {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t\tif _, err = assertion.NewVerifier(cfg.origins.Credential, origin, cfg.keys); err != nil {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t}\n\t\tif cfg.consumers[\"directory\"] != cfg.origins.Directory {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\tcase \"directory\":\n\t\tif dbPath == \"\" || os.Getenv(\"HOME_ASSERTION_KEY\") != \"\" {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.secrets.Sealer, err = LoadSealer()\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tvar encoded map[string]string\n\t\traw, err := exchangeJSON(\"HOME_ASSERTION_KEYS\", 4096)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\t\tif len(raw) > 4096 || json.Unmarshal([]byte(raw), &encoded) != nil || len(encoded) == 0 || len(encoded) > 8 {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.keys = make(map[string][]byte, len(encoded))\n\t\tfor kid, value := range encoded {\n\t\t\tkey, err := base64.StdEncoding.DecodeString(value)\n\t\t\tif err != nil {\n\t\t\t\treturn Runtime{}, errExchangeConfig\n\t\t\t}\n\t\t\tcfg.keys[kid] = key\n\t\t}\n\t\tif _, err = assertion.NewVerifier(cfg.origins.Credential, cfg.origins.Directory, cfg.keys); err != nil {\n\t\t\treturn Runtime{}, errExchangeConfig\n\t\t}\n\t\tcfg.roster, err = loadRosterRuntime(cfg.role, cfg.keys)\n\t\tif err != nil {\n\t\t\treturn Runtime{}, err\n\t\t}\n\tdefault:\n\t\treturn Runtime{}, errExchangeConfig\n\t}\n\treturn cfg, nil\n}\nfunc consumerName(s string) bool {\n\tif len(s) == 0 || len(s) > 64 {\n\t\treturn false\n\t}\n\tfor _, b := range []byte(s) {\n\t\tif !(b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' || b >= '0' && b <= '9' || b == '_' || b == '-') {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true"
+ },
+ {
+ "id": "S4",
+ "file": "internal/home/keys.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/keys.go",
+ "sha256": "4b4cb1c250c6b9827df4871108f4baa2ddde45976457c112bb70a9657fa41b48",
+ "line": 118,
+ "end_line": 172,
+ "excerpt": "func LoadSecrets(dbPath string, logger *slog.Logger) (Secrets, error) {\n\tif logger == nil {\n\t\tlogger = slog.Default()\n\t}\n\n\t// SQLite treats an empty filename as a private temporary database:\n\t// the app comes up, works, and loses every person on restart. There\n\t// is no warning for this anywhere below us, which is why it is\n\t// checked here.\n\tif strings.TrimSpace(dbPath) == \"\" {\n\t\treturn Secrets{}, errors.New(\"no database path: set Options.DBPath or pass -db, or SQLite opens a private temporary database and every person is lost on restart\")\n\t}\n\n\tvar s Secrets\n\tvar err error\n\n\t// Through LoadSealer rather than beside it, so HOME_DEK is read in\n\t// one place. Two readers of the same variable is how one of them\n\t// ends up with a check the other does not have.\n\ts.Sealer, err = LoadSealer()\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\n\tpepper, err := key32(\"HOME_PEPPER\")\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\ts.Pepper = pepper[:]\n\n\ts.SigninKey, err = key32(\"HOME_SIGNIN_KEY\")\n\tif err != nil {\n\t\treturn Secrets{}, err\n\t}\n\n\t// mail.FromEnv falls back to mail.Logged with a warning when HOST or\n\t// FROM is absent, and Logged's Send logs \"to\", to \u2014 an address into\n\t// platform-held logs on every single sign-in. A warning is not\n\t// enough: that log is storage we cannot grep or redact, so this is\n\t// the one fallback we refuse instead of accept.\n\t//\n\t// CARLOS_SMTP_PASS is a different failure and is refused for a\n\t// different reason, so the message below distinguishes them. It\n\t// leaks nothing: with HOST and FROM set, FromEnv returns the SMTP\n\t// sender whether or not PASS is present. What a missing PASS costs\n\t// is delivery \u2014 every link fails at send time on an app that\n\t// otherwise looks healthy. (It is inert without CARLOS_SMTP_USER,\n\t// which `carlos email enable` delivers alongside it; refusing on\n\t// PASS is a bet that the platform sets both or neither.)\n\t//\n\t// Deliberately no loopback relaxation. Sheets' LoadAuthEnv allows\n\t// one for local development, keyed on its instance origin being an\n\t// http loopback host. The home has no origin variable at this step,\n\t// so the equivalent carve-out would have to invent one, and a\n\t// carve-out that turns off the leak guard is not a thing to invent"
+ },
+ {
+ "id": "S5",
+ "file": "internal/home/origins.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/origins.go",
+ "sha256": "dc98e1a428ff5703a08ce24e674a121eb450e9155040e1854319d2449d9be851",
+ "line": 26,
+ "end_line": 67,
+ "excerpt": "func LoadOrigins() (Origins, error) {\n\tcredential, haveCredential := os.LookupEnv(\"HOME_CREDENTIAL_ORIGIN\")\n\tdirectory, haveDirectory := os.LookupEnv(\"HOME_DIRECTORY_ORIGIN\")\n\tif !haveCredential && !haveDirectory {\n\t\treturn Origins{Origin, directoryOrigin}, nil\n\t}\n\torigins := Origins{credential, directory}\n\tif !haveCredential || !haveDirectory {\n\t\treturn Origins{}, errOrigins\n\t}\n\treturn origins, origins.validate()\n}\n\nfunc originHost(origin string) (string, error) {\n\tu, err := url.Parse(origin)\n\tif err != nil || u.Scheme != \"https\" || u.User != nil || u.Host == \"\" || origin != \"https://\"+u.Host || u.Host != strings.ToLower(u.Host) || net.ParseIP(u.Host) != nil {\n\t\treturn \"\", errOrigins\n\t}\n\tif len(u.Host) > 253 {\n\t\treturn \"\", errOrigins\n\t}\n\tlabels := strings.Split(u.Host, \".\")\n\tif len(labels) < 2 {\n\t\treturn \"\", errOrigins\n\t}\n\tfor _, label := range labels {\n\t\tif len(label) == 0 || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' {\n\t\t\treturn \"\", errOrigins\n\t\t}\n\t\tfor _, c := range label {\n\t\t\tif !(c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '-') {\n\t\t\t\treturn \"\", errOrigins\n\t\t\t}\n\t\t}\n\t}\n\treturn u.Host, nil\n}\n\nfunc (o Origins) validate() error {\n\tcredential, err := originHost(o.Credential)\n\tif err != nil {\n\t\treturn err"
+ },
+ {
+ "id": "S6",
+ "file": "internal/home/roster_runtime.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/roster_runtime.go",
+ "sha256": "5e2ed41df26b1342834fe6996b5df901a2b05e9f4f41bb6afc98c6e8a7bd3c3c",
+ "line": 54,
+ "end_line": 105,
+ "excerpt": "func loadRosterRuntime(role string, credentialKeys map[string][]byte) (rosterRuntime, error) {\n\tmode, modeSet := os.LookupEnv(\"HOME_ROSTER_MODE\")\n\tencoded, keySet := os.LookupEnv(\"HOME_ROSTER_KEY\")\n\tif role != \"directory\" {\n\t\tif modeSet || keySet {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\treturn rosterRuntime{}, nil\n\t}\n\tif !modeSet {\n\t\tmode = \"disabled\"\n\t}\n\tif mode == \"disabled\" {\n\t\tif keySet {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\treturn rosterRuntime{mode: mode}, nil\n\t}\n\tif mode != \"serve\" || !keySet || len(encoded) > 4096 {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\traw, err := base64.StdEncoding.Strict().DecodeString(encoded)\n\tif err != nil || base64.StdEncoding.EncodeToString(raw) != encoded {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tvar fields struct {\n\t\tSign string `json:\"sign_priv_d\"`\n\t\tBox string `json:\"box_priv_d\"`\n\t}\n\tif json.Unmarshal(raw, &fields, json.RejectUnknownMembers(true)) != nil {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tfor _, s := range []string{fields.Sign, fields.Box} {\n\t\tb, e := hex.DecodeString(s)\n\t\tif e != nil || len(b) != 32 || hex.EncodeToString(b) != s {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t\td := new(big.Int).SetBytes(b)\n\t\tif d.Sign() <= 0 || d.Cmp(elliptic.P256().Params().N) >= 0 {\n\t\t\treturn rosterRuntime{}, errExchangeConfig\n\t\t}\n\t}\n\tkey, err := family.UnmarshalKeypair(raw)\n\tif err != nil || !validRosterKey(key) {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\tcfg := rosterRuntime{mode: mode, signer: key, keyID: rosterKeyID(key)}\n\tif !cfg.valid(role, credentialKeys) {\n\t\treturn rosterRuntime{}, errExchangeConfig\n\t}\n\treturn cfg, nil\n}"
+ },
+ {
+ "id": "S7",
+ "file": "internal/operator/protocol.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/protocol.go",
+ "sha256": "332ff9ccbdee79778486a49d54cd2c7c7f36fc0fd28a2770ee4a0f553316dba3",
+ "line": 54,
+ "end_line": 58,
+ "excerpt": "type Pins struct {\n\tRole, Origin, Installation, Registry, Device string\n\tPublicKey string\n\tActions []string\n}"
+ },
+ {
+ "id": "S8",
+ "file": "internal/operator/protocol.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/protocol.go",
+ "sha256": "332ff9ccbdee79778486a49d54cd2c7c7f36fc0fd28a2770ee4a0f553316dba3",
+ "line": 118,
+ "end_line": 118,
+ "excerpt": "func keyID(b []byte) string { h := sha256.Sum256(b); return hex.EncodeToString(h[:]) }"
+ },
+ {
+ "id": "S9",
+ "file": "internal/operator/directory.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/directory.go",
+ "sha256": "4071f042ee858f0b71aff414b7e0a2cc1ca1bf2598d941e14544db94bf90cf4e",
+ "line": 82,
+ "end_line": 121,
+ "excerpt": "func NewDirectory(engine *Engine, owner *OwnerVerifier, signer *family.Keypair, keys []roster.Key, policy directorydata.Config) (*Directory, error) {\n\tif engine == nil || engine.verifier.pins.Role != \"directory\" || owner == nil || owner.directory != engine.verifier.pins.Origin || !signingKey(signer) || len(keys) == 0 || len(keys) > 8 {\n\t\treturn nil, ErrRefused\n\t}\n\tnames, e := directorydata.New(engine.db, engine.sealer, policy)\n\tif e != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tseen := map[string]bool{}\n\tfor _, k := range [][]byte{engine.verifier.key, owner.key, signer.SignPub()} {\n\t\tif seen[string(k)] {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tseen[string(k)] = true\n\t}\n\tids := map[string]bool{}\n\tfor _, k := range keys {\n\t\tp, e := public(k.Public)\n\t\tif e != nil || !atom(k.ID, 64) || ids[k.ID] || seen[string(p)] {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tids[k.ID] = true\n\t\tseen[string(p)] = true\n\t}\n\td := &Directory{engine, owner, signer, append([]roster.Key(nil), keys...), names, policy, map[string]bool{}}\n\td.policy.Apps = append([]string(nil), policy.Apps...)\n\tfor _, app := range policy.Apps {\n\t\td.apps[app] = true\n\t}\n\treturn d, nil\n}\nfunc atom(s string, max int) bool {\n\tif len(s) == 0 || len(s) > max {\n\t\treturn false\n\t}\n\tfor _, c := range s {\n\t\tif !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' || c == '-') {\n\t\t\treturn false\n\t\t}\n\t}"
+ },
+ {
+ "id": "S10",
+ "file": "internal/operator/credential.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/credential.go",
+ "sha256": "327f2e53728f919b1cc63697816dd3898c6393b8bc003436b78a43bd6c5895fb",
+ "line": 34,
+ "end_line": 50,
+ "excerpt": "func NewCredential(engine *Engine, directory string, signer *family.Keypair, browserPublicKeys [][]byte, resolve PersonResolver) (*Credential, error) {\n\tif engine == nil || engine.verifier.pins.Role != \"credential\" || !Origin(directory) || directory == engine.verifier.pins.Origin || !signingKey(signer) || resolve == nil || len(browserPublicKeys) == 0 || len(browserPublicKeys) > 8 || bytes.Equal(signer.SignPub(), engine.verifier.key) {\n\t\treturn nil, ErrRefused\n\t}\n\tfor _, key := range browserPublicKeys {\n\t\tif _, e := public(base64.RawURLEncoding.EncodeToString(key)); e != nil {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tif bytes.Equal(key, signer.SignPub()) || bytes.Equal(key, engine.verifier.key) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t}\n\treturn &Credential{engine, directory, signer, resolve}, nil\n}\nfunc (c *Credential) Execute(ctx context.Context, raw []byte) ([]byte, error) {\n\treturn c.engine.Execute(ctx, raw, func(ctx context.Context, conn *sql.Conn, r Request) ([]byte, error) {\n\t\tvar in OwnerInput"
+ },
+ {
+ "id": "S11",
+ "file": "internal/operator/inspect.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/inspect.go",
+ "sha256": "53f03642dd419e369efbf5decfff291ce5b54c6efe91e5156c2c435b223fa541",
+ "line": 72,
+ "end_line": 132,
+ "excerpt": "func (d *Directory) Inspect(ctx context.Context, raw []byte) ([]byte, error) {\n\tif d == nil || d.engine == nil {\n\t\treturn nil, ErrRefused\n\t}\n\te := d.engine\n\tchallenge, err := e.verifier.verifyInspect(raw, e.now())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\tc, err := e.db.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer c.Close()\n\tif _, err = c.ExecContext(ctx, \"BEGIN\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer c.ExecContext(context.Background(), \"ROLLBACK\")\n\tvar count int\n\tif err = c.QueryRowContext(ctx, \"SELECT count(*) FROM directory_operator_state WHERE singleton=1 AND (origin!=? OR installation!=? OR registry!=? OR device!=? OR key_id!=? OR completed_at>?)\", e.verifier.pins.Origin, e.verifier.pins.Installation, e.verifier.pins.Registry, e.verifier.pins.Device, e.verifier.kid, e.now().Unix()).Scan(&count); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif count != 0 {\n\t\treturn nil, ErrRefused\n\t}\n\tvar generation *string\n\trows, err := c.QueryContext(ctx, \"SELECT generation FROM roster_generation WHERE singleton=1\")\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif rows.Next() {\n\t\tvar g string\n\t\tif rows.Scan(&g) != nil || !CanonicalToken(g) {\n\t\t\trows.Close()\n\t\t\treturn nil, ErrUnavailable\n\t\t}\n\t\tgeneration = &g\n\t}\n\terr = rows.Err()\n\tcloseErr := rows.Close()\n\tif err != nil || closeErr != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tid, sqid, err := nextTeam(ctx, c)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = e.verifier.verifyInspect(raw, e.now()); err != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tout, err := encode(Inspection{1, challenge.Challenge, e.now().Unix(), generation, id, sqid})\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = c.ExecContext(ctx, \"COMMIT\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\treturn out, nil\n}"
+ },
+ {
+ "id": "S12",
+ "file": "internal/operator/open_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/open_linux.go",
+ "sha256": "15ba8a2dc975a61d614c39e1cd3f7e7dc24f617140b893610d4954ae87b13c38",
+ "line": 52,
+ "end_line": 81,
+ "excerpt": "func newBoundDatabase(path string, device, inode uint64, deadline time.Time) (*boundDatabase, error) {\n\tif device == 0 || inode == 0 || !deadline.After(time.Now()) {\n\t\treturn nil, ErrRefused\n\t}\n\tpin, id, e := pinExisting(path)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tif id != (fileIdentity{device, inode}) {\n\t\tpin.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tc := &boundConnector{path: path, pin: pin, identity: id, deadline: deadline, sqlite: &sqlite.Driver{}}\n\tdb := sql.OpenDB(c)\n\tdb.SetMaxOpenConns(1)\n\tdb.SetMaxIdleConns(1)\n\treturn &boundDatabase{db, c}, nil\n}\nfunc (b *boundDatabase) close() error {\n\te := b.db.Close()\n\tb.connector.mu.Lock()\n\tdefer b.connector.mu.Unlock()\n\tif b.connector.active {\n\t\treturn ErrUnavailable\n\t}\n\tif x := b.connector.pin.Close(); e == nil {\n\t\te = x\n\t}\n\treturn e\n}"
+ },
+ {
+ "id": "S13",
+ "file": "internal/operator/open_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/open_linux.go",
+ "sha256": "15ba8a2dc975a61d614c39e1cd3f7e7dc24f617140b893610d4954ae87b13c38",
+ "line": 202,
+ "end_line": 283,
+ "excerpt": "func (c *boundConnector) Connect(ctx context.Context) (driver.Conn, error) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tif c.active || ctx.Err() != nil || c.pathMatches() != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tc.checkpoint(\"before-inventory\")\n\tbaseline, e := descriptors()\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tfor _, d := range baseline {\n\t\tif writable(d.flags) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t}\n\tc.checkpoint(\"before-open\")\n\tif c.pathMatches() != nil {\n\t\treturn nil, ErrRefused\n\t}\n\tc.checkpoint(\"before-driver\")\n\tu := url.URL{Scheme: \"file\", Path: c.path}\n\tq := u.Query()\n\tq.Set(\"mode\", \"rw\")\n\tu.RawQuery = q.Encode()\n\tnative, e := c.sqlite.Open(u.String())\n\tif e != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tkeep := false\n\tdefer func() {\n\t\tif !keep {\n\t\t\tnative.Close()\n\t\t}\n\t}()\n\tc.checkpoint(\"after-open\")\n\tcurrent, e := descriptors()\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\tmainFD := -1\n\tfor fd, d := range current {\n\t\tif !writable(d.flags) {\n\t\t\tcontinue\n\t\t}\n\t\tif _, old := baseline[fd]; old {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tif d.identity == c.identity {\n\t\t\tif d.flags&unix.O_ACCMODE != unix.O_RDWR || d.links != 1 || mainFD != -1 {\n\t\t\t\treturn nil, ErrRefused\n\t\t\t}\n\t\t\tmainFD = fd\n\t\t}\n\t}\n\tif mainFD < 0 {\n\t\treturn nil, ErrRefused\n\t}\n\tbound := &boundConnection{Conn: native, owner: c, mainFD: mainFD, siblings: map[string]fileIdentity{}}\n\tif e = bound.check(); e != nil {\n\t\treturn nil, e\n\t}\n\tquery, ok := native.(driver.QueryerContext)\n\tif !ok {\n\t\treturn nil, ErrRefused\n\t}\n\trows, e := query.QueryContext(ctx, \"PRAGMA database_list\", nil)\n\tif e != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tvalues := make([]driver.Value, 3)\n\tif rows.Next(values) != nil || values[1] != \"main\" || values[2] != c.path {\n\t\trows.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tif e = rows.Next(values); e != io.EOF {\n\t\trows.Close()\n\t\treturn nil, ErrRefused\n\t}\n\tif rows.Close() != nil {\n\t\treturn nil, ErrUnavailable\n\t}"
+ },
+ {
+ "id": "S14",
+ "file": "internal/operator/engine.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/engine.go",
+ "sha256": "76b234222e95df223158aac4fe34b0ab954e75892a0c86f088bcc7c0a9d6d125",
+ "line": 68,
+ "end_line": 137,
+ "excerpt": "func (e *Engine) Execute(ctx context.Context, raw []byte, mutate Mutation) ([]byte, error) {\n\tif e == nil || mutate == nil {\n\t\treturn nil, ErrRefused\n\t}\n\treq, err := e.verifier.Verify(raw)\n\tif err != nil {\n\t\treturn nil, ErrRefused\n\t}\n\ta := req.authorization\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\tconn, err := e.db.Conn(ctx)\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tdefer conn.Close()\n\tfor _, statement := range []string{\"PRAGMA foreign_keys=ON\", \"PRAGMA secure_delete=ON\", \"PRAGMA busy_timeout=1000\"} {\n\t\tif _, err = conn.ExecContext(ctx, statement); err != nil {\n\t\t\treturn nil, ErrUnavailable\n\t\t}\n\t}\n\tvar fk, secure int\n\tvar journal string\n\tif conn.QueryRowContext(ctx, \"PRAGMA foreign_keys\").Scan(&fk) != nil || fk != 1 || conn.QueryRowContext(ctx, \"PRAGMA secure_delete\").Scan(&secure) != nil || secure != 1 || conn.QueryRowContext(ctx, \"PRAGMA journal_mode\").Scan(&journal) != nil || journal != \"wal\" {\n\t\treturn nil, ErrUnavailable\n\t}\n\tviolations, err := conn.QueryContext(ctx, \"PRAGMA foreign_key_check\")\n\tif err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tbad := violations.Next()\n\treadErr := violations.Err()\n\tcloseErr := violations.Close()\n\tif bad || readErr != nil || closeErr != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif _, err = conn.ExecContext(ctx, \"BEGIN IMMEDIATE\"); err != nil {\n\t\treturn nil, ErrUnavailable\n\t}\n\tfinished := false\n\tdefer func() {\n\t\tif !finished {\n\t\t\tcleanup, cancel := context.WithTimeout(context.Background(), time.Second)\n\t\t\tdefer cancel()\n\t\t\tif _, err := conn.ExecContext(cleanup, \"ROLLBACK\"); err != nil {\n\t\t\t\t_ = conn.Raw(func(any) error { return driver.ErrBadConn })\n\t\t\t}\n\t\t}\n\t}()\n\tvar storedOrigin, storedInstallation, storedRegistry, storedDevice, storedHead, storedKey string\n\tvar storedSequence, storedCompleted int64\n\tstateErr := conn.QueryRowContext(ctx, \"SELECT origin,installation,registry,device,sequence,head,completed_at,key_id FROM \"+e.prefix+\"_state WHERE singleton=1\").Scan(&storedOrigin, &storedInstallation, &storedRegistry, &storedDevice, &storedSequence, &storedHead, &storedCompleted, &storedKey)\n\tif stateErr != nil && !errors.Is(stateErr, sql.ErrNoRows) {\n\t\treturn nil, ErrUnavailable\n\t}\n\tif stateErr == nil && (storedOrigin != a.Origin || storedInstallation != a.Installation || storedRegistry != a.Registry || storedDevice != a.Device || storedKey != e.verifier.kid || storedSequence <= 0 || !CanonicalToken(storedHead) || storedCompleted <= 0 || e.now().Unix() < storedCompleted) {\n\t\treturn nil, ErrRefused\n\t}\n\tvar oldAction, oldHead, oldOperator string\n\tvar oldSequence int64\n\tvar oldMAC, sealed []byte\n\terr = conn.QueryRowContext(ctx, \"SELECT action,sequence,authorization_head,request_mac,sealed_result,operator_ref FROM \"+e.prefix+\"_results WHERE operation_id=?\", a.OperationID).Scan(&oldAction, &oldSequence, &oldHead, &oldMAC, &sealed, &oldOperator)\n\tif err == nil {\n\t\tif stateErr != nil || storedSequence < a.Sequence || oldOperator != a.Device || oldAction != a.Action || oldSequence != a.Sequence || oldHead != req.head || !hmac.Equal(oldMAC, e.mac(req)) {\n\t\t\treturn nil, ErrRefused\n\t\t}\n\t\tresult, openErr := e.sealer.Open(e.purpose(a), sealed)\n\t\tif openErr != nil || len(result) == 0 || len(result) > InputLimit {\n\t\t\treturn nil, ErrUnavailable\n\t\t}"
+ },
+ {
+ "id": "S15",
+ "file": "internal/operator/verification.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/verification.go",
+ "sha256": "547fef12d2ccdab9a41a172677c0be37d8f1d04b0ada9bd9b15b5a3d7e332c71",
+ "line": 27,
+ "end_line": 51,
+ "excerpt": "type ActivationEvidence struct {\n\tVersion int `json:\"version\"`\n\tPolicy string `json:\"policy\"`\n\tAttempt string `json:\"attempt_id\"`\n\tConsumer string `json:\"consumer\"`\n\tTeamSQID string `json:\"team_sqid\"`\n\tApp string `json:\"app\"`\n\tAudience string `json:\"audience\"`\n\tGeneration string `json:\"generation\"`\n\tRecordSequence int64 `json:\"record_sequence\"`\n\tRecordDigest string `json:\"record_digest\"`\n\tEpoch int64 `json:\"epoch\"`\n\tOwner string `json:\"owner_ref\"`\n\tAppVersion string `json:\"app_version\"`\n\tArtifactDigest string `json:\"artifact_digest\"`\n\tEnvironmentBinding string `json:\"environment_binding\"`\n\tManifestDigest string `json:\"credential_manifest_digest\"`\n\tAliasHost string `json:\"alias_host\"`\n\tStarted int64 `json:\"started_at\"`\n\tCompleted int64 `json:\"completed_at\"`\n}\ntype ActivationInput struct {\n\tInputBase\n\tEvidence ActivationEvidence `json:\"evidence\"`\n}"
+ },
+ {
+ "id": "S16",
+ "file": "internal/operator/verification.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/verification.go",
+ "sha256": "547fef12d2ccdab9a41a172677c0be37d8f1d04b0ada9bd9b15b5a3d7e332c71",
+ "line": 182,
+ "end_line": 184,
+ "excerpt": "\tif e != nil || p.Version != 1 || p.Policy != \"oficina/team-activation/v1\" || !CanonicalToken(p.Attempt) || !version(p.AppVersion) || !CanonicalToken(p.ArtifactDigest) || !CanonicalToken(p.EnvironmentBinding) || !CanonicalToken(p.ManifestDigest) || p.AliasHost != u.Host || p.Started <= 0 || p.Completed < p.Started || p.Completed > now || now-p.Completed >= 300 {\n\t\treturn nil, ErrRefused\n\t}"
+ },
+ {
+ "id": "S17",
+ "file": "internal/provisioner/prepare_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/provisioner/prepare_linux.go",
+ "sha256": "4b04bb15b1d22bc825207548b0bb8d84266a4c03dc84af125ed91f260320f89e",
+ "line": 77,
+ "end_line": 141,
+ "excerpt": "func decodeOperationPlan(raw []byte) (OperationPlan, any, error) {\n\tvar p OperationPlan\n\tif len(raw) == 0 || len(raw) > operator.BodyLimit || json.Unmarshal(raw, &p, json.RejectUnknownMembers(true)) != nil || p.Version != 1 || !operator.CanonicalToken(p.Installation) || !operator.CanonicalToken(p.Operation) || len(p.Input) == 0 || len(p.Input) > operator.InputLimit {\n\t\treturn p, nil, ErrRefused\n\t}\n\tvar input any\n\tvar base *operator.InputBase\n\tswitch p.Action {\n\tcase \"directory.initialize\":\n\t\tin := new(operator.InitializeInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"credential.owner-seed\":\n\t\tin := new(operator.OwnerInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"directory.seed-team\":\n\t\tin := new(operator.SeedInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tcase \"directory.provision-consumer\":\n\t\tin := new(operator.ProvisionInput)\n\t\tinput = in\n\t\tbase = &in.InputBase\n\tdefault:\n\t\t// Verification and activation await checked record/evidence collectors.\n\t\treturn p, nil, ErrRefused\n\t}\n\trole := \"directory\"\n\tif p.Action == \"credential.owner-seed\" {\n\t\trole = \"credential\"\n\t}\n\tif p.Role != role || json.Unmarshal(p.Input, input, json.RejectUnknownMembers(true)) != nil || base.Version != 1 || base.Operation != p.Action || base.OperationID != p.Operation {\n\t\treturn p, nil, ErrRefused\n\t}\n\treturn p, input, nil\n}\nfunc preparationScope(s *installationState, input any) bool {\n\tif s == nil {\n\t\treturn false\n\t}\n\tswitch in := input.(type) {\n\tcase *operator.InitializeInput:\n\t\treturn in.ExpectedGeneration == nil && operator.CanonicalToken(in.Generation) && in.Baseline == \"operator-attests-never-provisioned\"\n\tcase *operator.OwnerInput:\n\t\tsqid, e := operator.TeamSQID(in.TeamID)\n\t\taddress, parseErr := mail.ParseAddress(in.Address)\n\t\treturn e == nil && parseErr == nil && address.Address == in.Address && address.Name == \"\" && in.ExistingOnly && in.TeamSQID == sqid && in.Directory == s.Plan.Directory.Origin && len(in.Address) > 0 && len(in.Address) <= 320\n\tcase *operator.SeedInput:\n\t\treturn in.Generation == s.Generation && s.Generation != \"\"\n\tcase *operator.ProvisionInput:\n\t\treturn in.Generation == s.Generation && s.Generation != \"\"\n\t}\n\treturn false\n}\nfunc prepareRequest(ctx context.Context, statePath, floorPath string, password, plan []byte, output *requestOutput) (PreparationInfo, error) {\n\tp, input, e := decodeOperationPlan(plan)\n\tif e != nil || output == nil {\n\t\treturn PreparationInfo{}, ErrRefused\n\t}\n\tj, e := existingJournal(statePath, floorPath, password)\n\tif e != nil {\n\t\treturn PreparationInfo{}, e\n\t}\n\tdefer closeExisting(j)"
+ },
+ {
+ "id": "S18",
+ "file": "cmd/home/main.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/cmd/home/main.go",
+ "sha256": "a414edf4e33e2be0293aeec50e5973bff7ad8978f0188b1c589547ab56522701",
+ "line": 52,
+ "end_line": 119,
+ "excerpt": "func main() {\n\tlogger := slog.Default()\n\n\t// DBPath is set here, not required as a flag \u2014 see the package\n\t// comment. Relative, so Resolve joins it to $STATE_DIRECTORY.\n\topts, err := rastrillo.Resolve(rastrillo.Options{Logger: logger, DBPath: \"home.db\"})\n\tif err != nil {\n\t\tlogger.Error(\"resolve\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// Every secret and setting whose absence is silent is validated\n\t// before anything serves. Each refusal here is a case where\n\t// continuing would produce an app that answers /healthz perfectly\n\t// well and is broken or leaking: no DEK and addresses persist in the\n\t// clear, no pepper and every person row is orphaned, no SMTP host\n\t// and magic links are written to platform-held logs instead of\n\t// emailed. The database path cannot be empty on this path \u2014 it is\n\t// set below \u2014 but LoadSecrets checks it anyway, for the caller that\n\t// builds its own Options.\n\truntime, err := home.LoadRuntime(opts.DBPath, logger)\n\tif err != nil {\n\t\tlogger.Error(\"config\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// Before db.Open, never after: Open calls Ping, which opens the\n\t// writer pool's single long-lived connection there and then, and a\n\t// hook registered afterwards misses it forever. That connection is\n\t// the only one that performs DELETEs.\n\thome.RegisterSecureDelete()\n\n\td, err := rdb.Open(opts.DBPath, logger)\n\tif err != nil {\n\t\tlogger.Error(\"open db\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer d.Close()\n\n\t// Ledgered, once at boot, forward-only. A boot that cannot reconcile\n\t// its schema refuses rather than guessing, same as a failed open.\n\tif _, err := migrate.Apply(context.Background(), d, runtime.Schema()); err != nil {\n\t\tlogger.Error(\"migrate\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\tapp, err := home.NewRuntime(runtime, d, logger)\n\tif err != nil {\n\t\tlogger.Error(\"wire app\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// rastrillo.Options.Mux wants a *http.ServeMux; the app's own\n\t// router is a chi.Router (an http.Handler), so it mounts under one.\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", app.Router())\n\topts.Mux = mux\n\topts.CSP = app.SecurityPolicy()\n\n\t// Blanked because this file opened the handle itself: Serve would\n\t// otherwise open a second one against the same file.\n\topts.DBPath = \"\"\n\n\tif err := rastrillo.Serve(opts); err != nil {\n\t\tlogger.Error(\"serve\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n}"
+ },
+ {
+ "id": "P1",
+ "absolute_path": "/home/paulca/amadan.net/carlos/platform/.claude/worktrees/overnight-always-awake-design/implementation/maintenance-exec.md",
+ "line": 55,
+ "end_line": 57,
+ "excerpt": "Resume is a separately approved operation, not `clear maintenance`. It names an expected serving release/artifact, configuration/key binding and successful app-specific compatibility-check command from that release. Platform verifies all pins under the fence/lease, runs the non-serving checker against the existing DB, verifies integrity/checkpoint and records its result. The app checker owns format/key/authorization compatibility; platform cannot infer it from exit of an earlier migration or a byte-compatible old binary. Docs TeamMode's minimum authorization-aware release floor is one such consumer requirement.\n\nOnly after the checker succeeds may the worker publish resume-ready evidence, install the pinned serving release/config and arrange the lease-to-serving replication handoff. Clear the fence through one guarded transition bound to this evidence; old/new worker races cannot resurrect a superseded resume. Admit HTTP only after the exact new process and replication are healthy and report the approved version; retain a durable resumed receipt. If process startup/replication/version verification fails, return to fenced/failed, not ready. The implementation must decide and test the precise lease handoff before code approval; simply releasing and hoping the next wake uses the approved pins is insufficient.",
+ "sha256": "82912e12d845b42179507362951a7b17ccf04632b9c59537e0f6b78246152335"
+ },
+ {
+ "file": "internal/home/models.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/models.go",
+ "sha256": "9bd9464bc57d545de1e26e6df65dbf8cbd3cd77706e68df8f5e2ce2aa8e541cc"
+ },
+ {
+ "file": "internal/home/migrations/0001_people.sql",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/migrations/0001_people.sql",
+ "sha256": "52de6c3fa2c323f0e7ba54c62f7c518811a4d684f4a76208647fe71e33e130fe"
+ },
+ {
+ "file": "internal/home/migrations/0002_signin_links.sql",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/migrations/0002_signin_links.sql",
+ "sha256": "8dc8b9c64f2b8222b7b2f3161a77de3903a26e436f1d9ee28552c984ff1ae884"
+ },
+ {
+ "file": "internal/home/directorydata/store.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/directorydata/store.go",
+ "sha256": "91093dfc24f44843c1bdbddd142ebbc2982d4fffeb083f50ea0002a30da971f8"
+ },
+ {
+ "file": "internal/home/directorydata/operator_schema.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/home/directorydata/operator_schema.go",
+ "sha256": "78183394b3782752213103ee6563e50d6e1857263ec2f639a50328899468d584"
+ },
+ {
+ "file": "internal/operator/engine.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/operator/engine.go",
+ "sha256": "76b234222e95df223158aac4fe34b0ab954e75892a0c86f088bcc7c0a9d6d125"
+ },
+ {
+ "file": "internal/provisioner/installations_linux.go",
+ "absolute_path": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare/internal/provisioner/installations_linux.go",
+ "sha256": "bf36cda8f341f620efcfd653329bad5acf5cc2bee8d4e8891e0e38f95c6b5810"
+ },
+ {
+ "module": "github.com/carlosframework/rastrillo@v0.23.0",
+ "file": "migrate/set.go",
+ "absolute_path": "/home/paulca/go/pkg/mod/github.com/carlosframework/rastrillo@v0.23.0/migrate/set.go",
+ "sha256": "cbf3ffcae75aaa1f50bb3c4772f52b6daf027d5a44e1bfaaec497fddf063f8eb"
+ },
+ {
+ "module": "github.com/carlosframework/rastrillo@v0.23.0",
+ "file": "migrate/schema.go",
+ "absolute_path": "/home/paulca/go/pkg/mod/github.com/carlosframework/rastrillo@v0.23.0/migrate/schema.go",
+ "sha256": "f1832cbd354fcadf49c3f43dd2b7d87ad0a8e4c6d6bd130414a2b31454630347"
+ },
+ {
+ "module": "github.com/carlosframework/rastrillo@v0.23.0",
+ "file": "migrate/apply.go",
+ "absolute_path": "/home/paulca/go/pkg/mod/github.com/carlosframework/rastrillo@v0.23.0/migrate/apply.go",
+ "sha256": "6ab9ea1dd6c63916f8d1984cf4a7c3a7cdf05e4705e807a34c58f7da5e537824"
+ }
+ ],
+ "review_note": "All concrete choices here are proposals; source reuse does not approve new key enrollment, readonly semantics, private protocol or platform authority."
+}
diff --git a/implementation/compatibility-checker/source-validation.json b/implementation/compatibility-checker/source-validation.json
new file mode 100644
index 0000000..a16e32c
--- /dev/null
+++ b/implementation/compatibility-checker/source-validation.json
@@ -0,0 +1,6 @@
+{
+ "home_revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "source_hashes_checked": 29,
+ "source_hash_mismatches": [],
+ "status": "unapproved design; no runtime implementation"
+}