| new file mode 100644 |
| index 0000000..b109684 |
| --- /dev/null |
| +++ b/implementation/compatibility-checker/proposal.json |
| @@ -0,0 +1,426 @@ |
| +{ |
| + "version": 4, |
| + "status": "UNAPPROVED revision4: pinned-library cleanup proof addresses PERSIST_WAL handoff blocker; design rereview required", |
| + "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. Distinctness means different key-family labels WITHIN one configured runtime, not different processes. Provisioner comparison must require credential browser_assertion active key among directory browser_assertion accepted keys and credential owner_seed active key equal directory owner_seed accepted key. Those intentional same-label cross-runtime equalities do not violate separation; their absence refuses integrated compatibility. No new global uniqueness rule across runtime roles.", |
| + "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. For operator sealed_result, rows contain no origin: derive the purpose origin from the corresponding stored operator_state.origin, first require equality with trusted expected origin. Missing/mismatched state with results present refuses; never derive origin from caller request or guess another origin until decryption works.", |
| + "directory_database_proof": "Authenticate every teams.sealed_name with directory.team-name/<id>, every directory operator sealed result with operator.result/v1/<origin>/<operation>/<action>, every oficina_handoff_pending.sealed_path with handoff.path.<stored secret_hash>, and every oficina_handoff_inbox.sealed_token with handoff.token.<stored handle_hash>. Read-only scan includes expired rows too; no sweep/Finish/Verify that consumes replay. Validate stored purpose/hash shape and bounded path representation using shared current fresh-prefix/SafePath rules; token decryption proves at-rest authentication, not current token validity or authority (expired tokens do not fail solely on expiry). Never emit plaintext or invoke handoff.Finish; discard per-row plaintext. Roster cursors and assertion intent are client-held, not persisted witnesses. For operator sealed_result, rows contain no origin: derive the purpose origin from the corresponding stored operator_state.origin, first require equality with trusted expected origin. Missing/mismatched state with results present refuses; never derive origin from caller request or guess another origin until decryption works.", |
| + "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 and role enrollment from verified closed-checkpoint handoff; exact role-specific schema; no creation/migration repair. Run read-only foreign_key_check within deadline and rely on fresh platform integrity/checkpoint receipt for whole-file integrity; avoid duplicating integrity_check. Corrupt schema/rows/ciphertexts or contradictory binding still refuse app compatibility.", |
| + "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. The frozen descriptor includes exactly the pinned replication-owned objects specified below, generated by executing their exact upstream DDL in the scratch build/test fixture; this does not create or repair objects on the real DB. Compare as a SET keyed by sqlite_schema type,name,tbl_name and normalized stored SQL (SQLite-produced spelling from exact fixture DDL), never row order, rowid or rootpage. Replication tables may predate app/operator migrations; physical page placement and creation order do not affect accepted identity. Structural field/SQL normalization must not erase constraints or expressions.", |
| + "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. The exact two replication-owned tables are shared infrastructure and explicitly allowed; they do not establish Home role identity.", |
| + "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. The exact two replication-owned tables are shared infrastructure and explicitly allowed; they do not establish Home role identity.", |
| + "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. Main byte hashing has separate256MiB per-pass cap and shared30second invocation deadline; these limits are conservative refusal limits, not a completeness claim for larger deployments.", |
| + "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.", |
| + "replication_owned_objects": { |
| + "profile": "Fixed benbjohnson/litestream v0.5.14 DB schema profile (also requires exact selected replication artifact compatibility; never infer from name prefix).", |
| + "ddl": [ |
| + "CREATE TABLE IF NOT EXISTS _litestream_seq (id INTEGER PRIMARY KEY, seq INTEGER);", |
| + "CREATE TABLE IF NOT EXISTS _litestream_lock (id INTEGER);" |
| + ], |
| + "required": "Both tables must exist after the required checkpoint handoff. Compare exact frozen SQLite structural/DDL descriptor generated by pinned driver replay of these statements. Reject extra columns, indexes, triggers, views, conflicting type or any other _litestream_* object. This is a fixed two-object admission rule, not a namespace wildcard. Neither table belongs in rastrillo_migrations; expected app migration ledger remains exact.", |
| + "contents": "_litestream_seq has zero or one row, and if present typeof(id)=integer,id=1,typeof(seq)=integer,1<=seq<=9223372036854775807. _litestream_lock must have zero rows. Query bounded LIMIT2 for seq and LIMIT1 for lock; refuse any row/value outside this shape. Checkpoint-written replication metadata is included in pre/post byte hash; checker never writes it.", |
| + "source": "github.com/benbjohnson/litestream@v0.5.14/db.go:1025-1034 fixed DDL;1395-1397 and2231 seq upsert; lock write transaction rolls back per source comment.", |
| + "compatibility": "A changed replication library schema requires reviewed profile update before using checker; no dynamic table learning or automatic whitelist expansion." |
| + } |
| + }, |
| + "database_opening": { |
| + "decision": "A checker-only actual-descriptor connector using mode=ro&immutable=1 is proposed exclusively for a verified closed-checkpoint handoff. No generic readonly fallback or mutable operator change. Absent handoff proof refuses before database opening.", |
| + "explicit_upstream_amendment": "home-operator-open.md line27 fixes mutable operator DSN to mode=rw/default VFS. This revision REQUESTS a separately reviewed checker-only exception mode=ro&immutable=1; it does not amend the mutable operator connector or claim its existing approval covers this path. The previously proposed checker no-immutable rule is replaced only under the preconditions below.", |
| + "worker_order": [ |
| + "Verify exact approved resume operation, exclusive operation execution and same primary/artifact/environment/DB identities. Install durable/local admission fence. Obtain checked old main+sidecar death, cgroup emptiness and old replication Close evidence BEFORE acquiring the maintenance Held lease.", |
| + "Under the same retained healthy Held lease and exclusive worker execution, invoke the separately proposed Held.Checkpoint protocol: temporary replica store SyncAndWait then checked Close; final lease health check. No Release or second owner. All store/SQLite handles used by checkpoint must be closed. Failure or uncertain close refuses handoff.", |
| + "This preparation is permitted only after fresh approval/fence/old writer and replica death under retained Held, never side-effect-free preflight. Litestream0.5.14 deliberately retains WAL/SHM via PERSIST_WAL1; do not require absence immediately after its Close. Open exactly one ordinary existing-only mode=rw SQLite connection through reviewed pinned DB and sidecar identity verification, with no global hooks or background jobs. This is worker preparation, not the readonly checker. Require one pool connection and no other SQLite/replication handle on the DB.", |
| + "On that ordinary connection, use the pinned modernc FileControl interface to set FileControlPersistWAL(\"main\",0), verify returned/readback0, run integrity_check requiring exactly ok, then PRAGMA wal_checkpoint(TRUNCATE) requiring busy=0,log=0,checkpointed=0. Unsupported file control, busy/incomplete checkpoint, integrity error, deadline/lease loss or uncertain identity refuses. Check all failures; no fallback/manual unlink or ignoring busy result. Return connection then checked DB.Close to perform last-connection SQLite cleanup. This close-time deletion is an explicitly proposed worker preparation effect under retained authority, never a checker mutation.", |
| + "After checked ordinary last close verify main one-link identity and actual ABSENCE of WAL/SHM/rollback-journal. Any remaining file, including zero-byte sidecar, refuses; never delete it to manufacture proof. Check lease health and exclusive executor still current. If actual pinned driver cannot complete cleanup, remain fenced/unavailable. Bind this fresh preparation+integrity receipt with Held.Checkpoint receipt into launch evidence; the exact receipt must identify source, operation and same lease rather than a free-standing success boolean.", |
| + "After closure and before checker launch, bind main length and SHA256 from an exact bounded scan to fresh attempt-specific private handoff evidence, alongside checkpoint receipt, old-writer/replica stop evidence, retained lease identity and current guard generation. Recheck absence/identity and healthy lease before dispatch.", |
| + "Launch only the exact selected checker artifact under immutable protected environment and reviewed read-only data namespace. Verify fresh handoff evidence through the platform launch verifier. The checker cannot mint evidence from a path, env flag, lease timestamp or its own observation.", |
| + "No writer, checkpoint, replication reopen, adoption or other checker may overlap this handoff interval. Worker retains lease/exclusive execution through checker closure, final evidence and resume transition. Any failure remains fenced. Existing ResumeFenced still owns subsequent compatible serving/replication handoff; checker never releases ownership.", |
| + "Preserve the protocol-required POST-checker independent integrity/checkpoint/restore and final serving handoff checks. This new pre-checker preparation supplies immutable-opening conditions only; it does not replace those checks, clear the fence or approve serving. Any post-checker checkpoint may recreate sidecars; that is outside the closed checker interval and must be handled by existing reviewed resume protocol." |
| + ], |
| + "executor_recovery": "A fresh lease, empty app cgroup or RecoverClaim alone does not prove an earlier maintenance executor is dead. Paused workerA could later checkpoint/reopen/publish while B checks immutable state. Takeover unavailable unless independently reviewed exclusive operation execution and predecessor executor quiescence/death/exclusion proof hold. No automatic timeout-based recovery or reuse of old handoff receipt.", |
| + "identity": "Retain existing nofollow ancestor walk, pinned parent and one-hardlink main device/inode, actual driver-open descriptor inventory, checks before/after every query/row and close. Expected driver main descriptor must be O_RDONLY and match the retained main identity. URI built by code with only fixed mode=ro,immutable=1,defaultVFS; no caller query params/hooks/extensions. Refuse O_RDWR/O_WRONLY, extra database, unexpected file descriptor, reconnect overlap, changed path or unlinked main. Immutable is safe only because separately proved ownership excludes ALL writers; it is not evidence that no writers exist. After pin acquisition and before driver open, freeze FD baseline. Require exactly ONE new O_RDONLY descriptor matching main device/inode in post-open FD delta; retained pin is already in baseline and cannot satisfy this test. Refuse no delta, multiple matching new FDs, writable/unlinked/temp regular descriptors or loss/reuse of a baseline FD. Apply same identity/descriptor checks across operation lifetime. Do not reuse mutable connector writable-only classification.", |
| + "os_boundary": "OS-readonly main and data namespace, including parent directory, are mandatory in addition to immutable mode. No writable regular inherited descriptors, application globals or SQLite hooks. App stdout is private anonymous pipe. This restricts this checker only; exclusion of other processes comes from verified fence/lease/executor protocol, never the mount alone. Before any query that may spill, apply only fixed connection-local PRAGMA temp_store=MEMORY and read it back. No request-controlled pragma, temp file, persistent journal or global SQLite hook. Memory remains bounded by platform tier and scan limits; allocation/limit failure refuses rather than spilling to disk.", |
| + "wal_shm": "Require WAL, SHM and rollback journal absent throughout before/during/after open; their appearance is refusal even if zero bytes. No SHM is opened or written, so there are no reader read-marks to classify as allowed changes. No sidecar creation/deletion, recovery, checkpoint, journal mode changes or writer repair in checker. Do not admit hot WAL or manufacture absent-sidecar state by removing files.", |
| + "byte_evidence": "Max main size256MiB, positive file length; bound exact each-pass byte count before reading and recheck EOF/length. SHA256 before SQLite open and after successful SQLite close, each at most256MiB, plus identity/size/sidecar absence checks. Worker prelaunch hash is also max256MiB; total required hash IO across worker+checker is at most768MiB. Use fixed64KiB streaming buffers, never os.ReadFile or full-file allocation. No stat-only equality claim: device/inode/size detect identity, cryptographic byte equality detects content.", |
| + "descriptor_lifetime": "Checker acquires and retains read-only pinned main descriptor before driver construction; prehash via that descriptor before SQL open and posthash via the SAME descriptor only after all SQLite connections close. Never open/close a second main-file descriptor while SQLite locks may exist. Use ReadAt/Seek on retained descriptor rather than reopening path. Keep it until hash/identity/sidecar checks finish. Close failure, partial scan, unexpected EOF/growth, deadline or mismatch prevents success. Worker independent observer holds its own stable descriptor and closes outside any local SQLite active connection.", |
| + "deadline": "Entire invocation including both checker hashes and SQL scan is bounded by min(verified launch deadline,30seconds) and conservative retained-lease deadline. Check context between64KiB reads; blocking kernel IO is supervised by platform containment/deadline and failure cannot be reported as checked stop. No success emitted if cleanup/posthash cannot finish within deadline. Larger/slower DB refuses, never sampling or extending lease authority.", |
| + "postcondition": "Before emitting any success bytes, verify driver close succeeded, exact pre/post main hashes match the fresh worker handoff hash, identity/size still match and all three sidecars remain absent. Worker accepts result only for exact live attempt with retained healthy lease and exclusive ownership, and independently rechecks identity/absence before resume. A hash is byte evidence under the no-writer protocol, not proof against a hostile trusted worker that changes and restores bytes.", |
| + "actual_driver_gate": "Required empirical positive: exact pinned modernc/native Linux, WAL-mode header but cleanly checkpointed/closed main with no sidecars, actual mode=ro&immutable=1 O_RDONLY inode descriptor, byte preservation and no sidecar creation. Negative: current mode=rw+query_only housekeeping probe, missing handoff, hot/empty WAL, SHM, journal, stale lease/worker, inode replacement and >256MiB all refuse. No VFS/unsafe introspection/dependency fork; failure means unsupported, not fallback. Enforce temp-file prohibition through actual descriptor inventory (including unlinked writable temp files), not merely temp_store readback: SQLITE_TEMP_STORE compile options may override pragma. Test forced spill/refusal on actual build; bound memory and fail closed. Positive local library proof is in probe/closed-checkpoint-proof.json, separate from future actual pinned-descriptor checker proof.", |
| + "root_probe": "Historical probe/observation.json demonstrates current mutable connector changes main/removes WAL+SHM despite only SELECT/query_only. It remains a negative control; it does not prove the proposed immutable connector or worker handoff exists.", |
| + "approval_provenance": "maintenance-exec.md P1 names the desired retained-lease checkpoint/stop protocol, but its file retains pending-approval status text. Treat those dependencies as separately proposed/reviewed artifacts whose exact approval and implementation receipts must be verified at integration. Neither this checker design nor references to parent work approve or supply checkpoint/launch/executor capability. Explicit immutable exception and integrity-before-hash ordering are requests for this dependency contract. Protocol owner confirms the pre-checker sequence is an additive app/worker-preparation dependency under the same approved operation, not preflight or a new wire/state transition; actual implementation still needs review. Local pinned-library proof establishes mechanics only, not deployed containment, file binding, namespace isolation or authority." |
| + }, |
| + "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. Additionally require fresh verified closed-checkpoint handoff evidence binding main identity/length/SHA256, absent WAL/SHM/journal, old writer/replica stop proof and same retained lease/exclusive executor. Evidence format belongs to reviewed platform launch adapter; this checker design requests required semantics, not a new self-signed authorization.", |
| + "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. Include private checked main SHA256/length and opaque handoff evidence digest solely for exact worker comparison, never public logging or release metadata.", |
| + "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.", |
| + "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.", |
| + "Exact cleanly closed WAL-mode main without sidecars succeeds under verified handoff and readonly immutable actual driver; current mode=rw probe remains a forbidden negative control. Preserve main bytes and sidecar absence at all observations.", |
| + "Every present sidecar (including zero-byte WAL/SHM and rollback journal), missing receipt, mismatched main hash/identity/length or writable main descriptor refuses before success. No cleanup deletion to manufacture acceptance.", |
| + "Interleave paused previous executorA with attempted fresh takeoverB: B cannot launch even with empty app cgroup/new lease until A is independently excluded. Interleave rogue reopen between checkpoint/launch: guard/executor enforcement prevents it, not hash timing alone.", |
| + "Handoff rows: wrong key, purpose or moved ciphertext refuses; legitimate expired token still decrypts without mint/consume/sweep; raw DB/session/replay/authority rows unchanged.", |
| + "Main256MiB exact-bound scans, over-bound refusal, short read, file growth, same-size mutation, inode swap, close/posthash failure and deadline cancellation all prevent any success bytes. Demonstrate no second main-descriptor open/close while SQL active.", |
| + "Remove immutable restriction-to-verified-handoff, sidecar absence, final byte comparison or handoff ciphertext checks in meaningful mutations: each must be killed.", |
| + "Actual replicated synthetic Home fixture after pinned Litestream open/checkpoint/close passes exact2-table profile; application ledger remains unchanged and no repair writes occur. Missing table, extra prefix object, added trigger/index, seq id!=1/NULL/noninteger/out-of-range/second row and nonempty lock all refuse.", |
| + "Mutations skipping replication row checks, excluding replication metadata from byte hashes, accepting retained pin as driver FD, omitting temp_store=MEMORY, or allowing wrong cross-runtime expected key equality must fail tests.", |
| + "Platform integrity must complete and close before hash/handoff. A stale/after-checker integrity receipt cannot satisfy prelaunch requirement.", |
| + "Pinned actual Held/Litestream/modernc proof: after Held.Checkpoint sidecars remain; ordinary FileControlPersistWAL0 + integrity + TRUNCATE + checkedlastclose removes them without unlink; same renewer/lease remains healthy, peer acquisition refused, replica restores unchanged logical data, immutable read preserves main hash/absence.", |
| + "Negative PERSIST_WAL1 on preparation connection retains sidecars and prevents success. Also test busy TRUNCATE, unsupported control, failedclose, lease loss and wrong inode: no checker launch. Synthetic proof does not substitute for integration tests of these failure cases.", |
| + "Run preparation only after fresh authorized execution and fence, never preflight. Mandatory independent post-checker integrity/checkpoint/restore remains executed; mutation skipping it must fail.", |
| + "Descriptor profile accepts replication tables created before additive migrations with changed rootpages/order, but refuses changed constraints/indexes/triggers/contents; actual temp spill is refused even when pragma readback reports memory." |
| + ], |
| + "unresolved_review_dependencies": [ |
| + "Checker-only exception to approved mutable operator mode=rw contract, reviewed immutable readonly descriptor connector and verified closed-checkpoint launch evidence are required. No existing Checkpoint receipt alone asserts absent sidecars or exclusive predecessor executor death; integrations must implement and prove those facts. Unsupported state remains unavailable.", |
| + "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": "R4 addresses R3 PERSIST_WAL blocker using actual pinned-library/local Held proof. This is a complete proposed preparation dependency with post-checker checks preserved; runtime authority and deployment not inferred." |
| +} |