1192 Commits
Author SHA1 Message Date
DanConwayDev d71d888019 Merge #9698b1f9: test: eliminate shared fixture races and timing-depend…
test: eliminate shared fixture races and timing-dependent assertions

nostr:nevent1qgsx2lyl2e4zvfadwcvkd9fkrcwczj7mf858hy85mwqclwgut8wpg2spz3mhxue69uhhyetvv9ujumn8d96zuer9wcq3yamnwvaz7tm8d96xummnw3ezucm0d5q3kamnwvaz7tmwva5hgtnyv9hxxmmwwashjer9wchxxmmdqqsfdx93lyfyyuvw79qg8qe4eec4gjxkqasu3glrrsljhdgle3hw5fqtx4mfz

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

CoverNote:

Parallel tests could lose released relay ports, leave connections alive after fixture shutdown, block Git children on full pipes, or infer readiness from scheduler-dependent sleeps. This revision extends the existing relay-port PR into one consolidated reliability proposal for Grasp.

- Retain SDK relay listeners through startup and exercise 32 concurrent fixtures.
- Transfer reserved loopback sockets into Grasp subprocesses through a private Unix test protocol, retain the address across restart, and keep offline/recovering endpoints continuously owned.
- Own HTTP, WebSocket upgrade and backend-forwarding tasks across the mock relay, auth gate, Git servers and proxy fixtures. Explicit shutdown cancels and joins requests; Git subprocess I/O drains concurrently.
- Wait for event visibility and actual connected-state metrics; correct metrics URL construction and stopped-source bookkeeping.
- Replace expiry scheduling margins with explicit timestamps and streaming sleeps/frame assumptions with observable gates and byte-level assertions.

Tests remain enabled and parallel. Normal server binding and service configuration are unchanged; inherited listener support requires NGIT_TEST=1 and validates a listening loopback socket. The private capability probe lets the companion ngit harness retain compatibility with older releases.

Targeted Linux validation in the repository development shell: 65 relay-connection tests, 33 rejected-index tests, 132 purgatory tests, all 3 streaming tests, 7 shared Git-server tests, and relay-identity/recovery tests passed. Final fixture_lifecycle passed 57 tests; the moved subprocess-restart regression passed separately. Scoped Clippy for fixture_lifecycle and relay_identity passed with warnings denied. A smoke test queried this Grasp binary using the modified ngit harness. Formatting and whitespace checks pass.

These checks are scoped, not a claim of full workspace, nixpkgs sandbox or Darwin validation. Full host builds remain outstanding for the new changes. External Buzz service fixtures are outside this PR. The separate ngit reliability proposal addresses the equivalent harness and Blossom timing issues.

AI assistance: implemented and reviewed with Codex (GPT-6).
2026-09-12 15:53:41 +01:00
DanConwayDev cac1256fb5 docs(test): record fixture ownership and timing contracts
Document the private test listener protocol, bounded observable readiness,
connection ownership and controlled timing assertions so new fixtures do
not reintroduce the same races. Replace advice to rerun transient failures
with instructions to preserve evidence and diagnose the underlying cause.

The listener environment is test-only rather than deployment configuration;
normal service configuration and the NixOS module are deliberately unchanged.
Validation: checked guidance against the implementation and targeted test
commands; formatting and whitespace checks pass.

Assisted-by: Codex (GPT-6)
2026-09-12 14:49:09 +00:00
DanConwayDev 59a37b660a test: cancel proxy connections when fixtures stop
Stopping accept loops left detached relay/proxy sessions alive. Track HTTP,
WebSocket upgrade and forwarding tasks under their owning fixture, cancel
them on shutdown, and drain cancellation before explicit stop returns.

Preserve censoring, rate limits, authentication and simulated disconnect
behavior. Add regressions that observe a live protocol exchange before
asserting the connection closes on stop, all under bounded deadlines.
Validation: fixture lifecycle checks passed for censoring, REQ/NEG limiting,
flapping and setup-drop relays. Auth-gating and upload proxy shutdown
regressions passed through relay_identity's common helper tests.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:26 +00:00
DanConwayDev 3c77e76a1f test(git): own request tasks and avoid pipe backpressure deadlocks
Detached HTTP tasks could outlive stopped Git fixtures. Sequential stdin and
output handling could deadlock when a child filled stdout or stderr before
consuming input. Own connection tasks, cancel Git children with their request,
and drain both outputs concurrently with stdin.

Keep fixture HTTP semantics and repository layout unchanged. A bound owned
listener replaces the unnecessary startup grace loop. Explicit stop joins
cancelled tasks while synchronous drop aborts the owner.
Validation: all seven shared SmartGitServer tests passed, including live
connection shutdown and one-MiB concurrent pipe traffic.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:26 +00:00
DanConwayDev cf2ec36a68 test(sync): wait for observable fixture readiness
Fixed startup and promotion sleeps could expire before asynchronous work
completed. Wait with bounded deadlines for event visibility and an actual
connected gauge; connection attempts and health do not prove readiness.

Preserve URL schemes when constructing metrics endpoints, retain ownership
of unavailable endpoints, and remove stopped sources instead of replacing
them with a live placeholder. Keep immediate assertions where completion
already guarantees the result. Production sync policy is unchanged.

Validation: shared sync helper tests passed; relay_identity and the fixture
lifecycle target compiled and passed with the revised common helpers.
Full sync and deletion integration execution remains host validation.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:26 +00:00
DanConwayDev 75da9a8446 test: preserve subprocess and recovery fixture listeners
Releasing a reservation before spawn or recovery allowed unrelated tests to
take the same port. Transfer the socket across exec through a private Unix
test-only protocol, retaining a parent copy across Grasp restarts. Validate
the inherited descriptor and keep it out of Git and SSH descendants.

Offline identity fixtures retain an accept-and-close endpoint until recovery.
Mock relay listeners and upgraded connections remain owned until shutdown.
Use real HTTP or SDK readiness instead of grace sleeps; startup errors in
the owned-listener path are not retried.

Normal server startup and deployment configuration are unchanged. The
capability probe permits older external harnesses to remain compatible.
Validation: listener adoption unit tests passed; relay_identity passed with
recovery coverage, MockRelay shutdown passed, and a real subprocess restart
plus a cross-repository ngit harness smoke test passed. Full platform builds
remain host validation.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:16 +00:00
DanConwayDev 1187cc062e test(git): synchronize streaming assertions with explicit gates
Sleeping fake Git processes and assumed HTTP frame boundaries made streaming
checks depend on scheduler timing. Hold fake Git behind an owned loopback
gate until the test observes the expected prefix; collect bytes independently
of frame splits and explicitly release subprocess progress.

Keep terminal-flush, promotion and cleanup ordering assertions. Gate waits
have bounded deadlines; no production streaming code changes are included.
Validation: all three git_response_streaming tests passed.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:16 +00:00
DanConwayDev 6d05e7eb05 test: remove scheduling margins from expiry assertions
Short real-time TTLs and sleep-based ordering made cache and purgatory tests
sensitive to host load. Age private cache timestamps explicitly and compare
queue or persistence deadlines against timestamps bracketing the operation.

Production clocks and expiry policy are unchanged. Retain tests for both
cache tiers, remaining TTL, queue deadlines and persisted expiry values.
Validation: 33 rejected-index and 132 purgatory tests passed in the offline
repository development shell.

Assisted-by: Codex (GPT-6)
2026-09-12 14:48:16 +00:00
DanConwayDev 7c144cc096 test(sync): retain relay listeners through startup
The SDK local relay probes and releases an available port before run binds
it again. Another socket can claim that port in between, causing AddrInUse
in parallel relay-connection tests. Passing port zero alone also leaves the
SDK URL pointing to zero in the locked dependency version.

Use a test-only listener bound to loopback port zero and retain it for the
fixture lifetime. Upgrade HTTP connections and pass their streams to the
SDK relay handler, preserving relay policies and subscription behavior.
Own connection tasks in a JoinSet and abort them with the fixture. Move all
ten affected test relay startups to this fixture; production is unchanged.

Add coverage that starts 32 relays concurrently and connects to their
unique actual bound addresses, using bounded handshake/close deadlines.
Do not disable tests, serialize the suite, or retry occupied ports.

Validation: all 65 relay-connection tests pass, including the previously
failing tail-group restoration test and the concurrent-listener regression.
Full Rust formatting and whitespace checks pass. Backport applies cleanly
to 3.0.2. Full nixpkgs host validation remains pending.

Assisted-by: Codex (GPT-6)
2026-09-12 14:10:15 +00:00
DanConwayDev 3a6de13568 Merge #edc95f2b: test(sync): simulate downtime in checkpoint integratio…
test(sync): simulate downtime in checkpoint integration test

nostr:nevent1qgsx2lyl2e4zvfadwcvkd9fkrcwczj7mf858hy85mwqclwgut8wpg2spz3mhxue69uhhyetvv9ujumn8d96zuer9wcq3yamnwvaz7tm8d96xummnw3ezucm0d5q3kamnwvaz7tmwva5hgtnyv9hxxmmwwashjer9wchxxmmdqqswmj2l9wqv8gnmety86n59j6j2vnmdr4rvg3nhlsnadudp4v0nuggz2q9ml

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

The checkpoint integration test can fail on a loaded builder because its 75 ms sleep leaves only 25 ms before the cold index expires. The nixpkgs 3.0.2 build observed `cold_expired == 1` where the test expected zero.

Simulate two minutes of downtime by editing the temporary checkpoint's `saved_at` field, with hot/cold retention periods of one minute and one week. Keep every existing assertion and leave production behavior unchanged. This extends the approach already applied to the equivalent unit tests in commit 14170f202f to the integration test that retained the sleep.

Validation: independent review, Rust formatting, whitespace checks and application to the released 3.0.2 source passed. Full Rust test execution remains pending in CI and the host nixpkgs build. The proposed nixpkgs package carries the matching test-only patch until a release includes the correction.

AI assistance: Codex (GPT-6) prepared the correction and PR, with an independent agent review. Publication uses dcagent.
2026-09-12 14:50:03 +01:00
DanConwayDev 3f8125fdaf test(sync): simulate downtime in checkpoint integration test
The persistence integration test sleeps 75 ms between 50 ms hot-cache and
100 ms cold-index expiry deadlines. Snapshot writes and host scheduling
can consume the remaining margin, legitimately expiring both tiers.
A sandboxed nixpkgs build exposed this after the streaming tests passed.

Set the persisted saved_at timestamp back two minutes and use minute/week
retention periods. This follows the synthetic-checkpoint approach already
used by the rejected-index unit tests in 14170f202f.
Retain all assertions so restoration must expire hot data while preserving
cold metadata. Production persistence and expiry behavior are unchanged.

Validation: independent review, rustfmt, git diff --check and patch
application to the released 3.0.2 source pass. Full test execution remains
pending in upstream CI and the host nixpkgs build; no heavy build ran here.

Assisted-by: Codex (GPT-6)
2026-09-12 13:47:01 +00:00
DanConwayDev 49d94d8a05 Merge #54658b4c: ci: publish release tags to crates.io from Nostr CI
nostr:nevent1qgsx2lyl2e4zvfadwcvkd9fkrcwczj7mf858hy85mwqclwgut8wpg2spz3mhxue69uhhyetvv9ujumn8d96zuer9wcq3yamnwvaz7tm8d96xummnw3ezucm0d5q3kamnwvaz7tmwva5hgtnyv9hxxmmwwashjer9wchxxmmdqqs9gevtf3cnx2t8m5h7cxyzcda7ygcf9pld6kdkcq4l90sfcr2m45qvcet5s

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

Crates.io publication is a manual release step even though Nostr CI already validates tagged commits. Publish after the existing lint, formatting and test steps succeed, using a repository-scoped CARGO_REGISTRY_TOKEN secret only in the publication step.

Require a push event on a v-prefixed tag and an exact manifest-version match. Use Cargo package verification and --locked against the explicit crates-io registry. Only ngit-grasp is selected; grasp-audit remains unpublished.

This assumes the coordinator has the scoped token configured and the tagged commit contains this workflow. It does not change archive/NIP-82 publication, stable promotion, documentation sync or registry versions; no live crate was uploaded during development.

Validated workflow syntax with actionlint, matching/mismatched tag and missing-secret cases with an intercepted publish command, Cargo packaging without upload, cargo fmt --all -- --check, and git diff --cached --check.
2026-09-12 07:57:02 +01:00
DanConwayDev 2b93d25fdd ci: publish release tags to crates.io from Nostr CI
Crates.io publication is a manual release step even though Nostr CI already validates tagged commits. Publish after the existing lint, formatting and test steps succeed, using a repository-scoped CARGO_REGISTRY_TOKEN secret only in the publication step.

Require a push event on a v-prefixed tag and an exact manifest-version match. Use Cargo package verification and --locked against the explicit crates-io registry. Only ngit-grasp is selected; grasp-audit remains unpublished.

This assumes the coordinator has the scoped token configured and the tagged commit contains this workflow. It does not change archive/NIP-82 publication, stable promotion, documentation sync or registry versions; no live crate was uploaded during development.

Validated workflow syntax with actionlint, matching/mismatched tag and missing-secret cases with an intercepted publish command, Cargo packaging without upload, cargo fmt --all -- --check, and git diff --cached --check.
2026-09-12 06:41:52 +00:00
DanConwayDev cdda4a23fe chore(release): prepare v3.0.2
Promote the already-reviewed release automation, documentation export metadata, canonical project references, and deterministic packaging fixtures as a stable maintenance release without changing production runtime behavior.

Move the accumulated Unreleased entries into a dated v3.0.2 section and align the Cargo and Nix package versions. The implementation remains isolated in the preceding merge commits.

Correctness relies on the Cargo manifest, lockfile, and Nix module declaring the same version. The OCI release behavior was validated by the green pull-request workflow, and the documentation exporter remains independently reviewable in its merge.

This commit deliberately excludes runtime changes, a grasp-audit version bump, the release tag, and publication. Validation is limited to release-metadata consistency and diff checks; the full suite is left to CI.
v3.0.2
2026-09-11 06:45:44 +00:00
DanConwayDev 68347956ed Merge #e924d285: feat(cli): export deterministic documentation schema
nostr:nevent1qqswjfxjs5ckkaqrnnz64ds0uj5csfpqukdncffgdw0cgup844e85mspz3mhxue69uhhyetvv9ujumn8d96zuer9wc0ewdc3

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

Documentation builds need a source-owned view of ngit-grasp commands and runtime configuration without copying Clap help or operator defaults into another repository.

Add an early hidden __docs-export dispatch that serializes schema-v1 command metadata, deduplicated public environment options, runtime constraints, dotenv behavior, and relay-owner secret precedence. Clap remains authoritative for reflectable facts; a narrow explicit registry covers validation and the skipped secret.

Correctness assumes Config::validate relationships continue to be mirrored in the constraint registry when they change. Secret source metadata intentionally contains locations and precedence only, never loaded values.

This does not publish artifacts, generate ngit.dev pages, expose internal test switches, model conditional Clap requirements that stable reflection cannot expose, or change normal relay and maintenance-command behavior.

Validated with cargo fmt --check, targeted unit and startup-isolation integration tests, all-target/all-feature clippy with warnings denied, deterministic process-output comparison, and jq schema assertions.
2026-09-11 06:42:46 +00:00
DanConwayDev 503cc73d05 Merge #e47035b4: Publish OCI container images through Nostr
nostr:nevent1qqswgup4ksq366entxj3x839l25wvaul64jysk7jjdc90x0espxt4lqpz3mhxue69uhhyetvv9ujumn8d96zuer9wc2zhwln

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

Build release images as OCI layouts, publish their signed tag maps and blobs through Nostr and Blossom, and verify the public ncontainer pull before completing a release.

The deployment PR pipeline now imports and runs the exact OCI layout produced by the shared release helper. A maintainer-only backfill workflow can publish and verify an exact prior version such as 3.0.1 without moving latest. This PR deliberately leaves package versions at 3.0.1; the v3.0.2 bump follows only after CI and merge.
2026-09-11 06:37:50 +00:00
DanConwayDev 5fed50e5e3 ci(release): publish OCI container images
Motivation: Release images should be built, checked, published, and consumed through the same Nostr-native OCI path operators will use, without relying on an unreviewed local release procedure.

Approach: Add a checked-in container manifest, a Docker-to-OCI layout helper, automatic tag publication and pull verification, a safe exact-tag backfill workflow, and deployment CI that imports and runs the exact generated layout.

Correctness: Release tags come only from reviewed OCI index annotations; ordinary publication preserves prior tags; historical backfills cannot move latest or prerelease channels; generated images and temporary resources use bounded, validated names and cleanup.

Excluded scope: This change does not alter ngit-grasp runtime behavior, change package versions, create v3.0.2, publish a container, move a release tag, or run the heavyweight container build in the coding VM.

Validation: git diff --check; shellcheck on all container scripts; actionlint on all affected workflows; ngit parsing of .ngit/containers.yaml; canonical source and v3.0.1 tag resolution. The PR pipeline performs the full OCI build, import, and deployment test.

Assisted-by: Codex (GPT-5)
2026-09-10 15:30:13 +00:00
DanConwayDev 4a9f327333 Merge #78bd49f0: test(git): make bare repository fixtures deterministic
nostr:nevent1qqs8302f7zcn0dvu02cfa59jdv620nj0xw5cqkzy3ksa84fa3w47cmspz3mhxue69uhhyetvv9ujumn8d96zuer9wcwwk7lv

PR-Author: DanConwayDev
nostr:npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr
2026-09-10 10:47:58 +00:00
DanConwayDev 929b195b05 test(git): silence bare repository fixtures
Two subprocess tests invoked git init through an inherited stdout and stderr without quiet mode. Clean Nix builds therefore printed Git's default-branch advice and repository initialization message twice in the test log.

Initialize the fixture explicitly on main and pass --quiet so it is independent of ambient branch configuration and emits no routine setup output. Production subprocess behavior is unchanged.

Validation: cargo fmt --all -- --check; cargo test -p ngit-grasp --lib git::subprocess::tests:: -- --nocapture.

Assisted-by: Codex (GPT-5)
2026-09-10 10:03:02 +00:00
DanConwayDev ef3a11a62e test(migration): initialize shallow origin on main
The shallow-backup fixture populated refs/heads/main but left the bare repository HEAD on Git's configurable default branch. In clean Nix builds that default is master, so clone succeeded as an empty repository and never wrote the shallow marker the test requires.

Initialize the fixture explicitly on main so HEAD names the populated branch and the depth-one clone deterministically exercises shallow migration behavior. Production migration code is unchanged.

Validation: cargo fmt --check; cargo test -p ngit-grasp --lib shallow_legacy_backup_waits_for_family_closure.

Assisted-by: Codex (GPT-5)
2026-09-10 08:46:18 +00:00
DanConwayDev b990d2189b docs(maintainers): point to shared protocol guide
The maintainer implementation guide moved out of the ngit client repository so implementations need a stable cross-project authority.

Link the canonical ngit-docs source and published guide from agent guidance and the relay architecture, and update the repository-state decision to name that guide as its model.

This assumes the source and published locations recorded by ngit's move commit are canonical. Runtime behavior and the existing relay-specific model description are deliberately unchanged.

Validated with git diff --cached --check and a repository-wide stale-reference scan.
2026-09-08 08:17:49 +00:00
DanConwayDev 3f8157693f docs: point GRASP references at Nostr Git
Move current GRASP specification links from GitHub to GitWorkshop.

Link audit output to its exact pinned specification commit.

Use NIP-05 cloning for ngit-grasp and ngit.dev for the ngit homepage.

Leave the archived migration link unchanged as a historical record.

Validated with rustfmt and the 54-test grasp-audit library suite.
2026-09-04 13:59:46 +00:00
DanConwayDev 7533e369d3 ci(release): derive prerelease publication channel
Derive the NIP-82 channel from the first prerelease identifier in the tagged version, while retaining main for stable versions. Pass the result explicitly to ngit so rc, beta, and similarly named channels are not mislabeled by the manifest default.

The application metadata and publication targets are unchanged. This deliberately does not trigger or otherwise rehearse a production release.

Validated with actionlint, yq, git diff --check, and stable/rc/beta/nightly derivation examples.
2026-09-03 13:47:09 +00:00
DanConwayDev 6162dd41b7 ci(release): rely on signed asset checksums
Motivation: NIP-82 asset events already bind release files to their SHA-256, while publishing a second platform-agnostic SHA256SUMS asset is redundant and rejected by catalogs that require an f tag.

Approach: package and upload only the static archive, document the signed-checksum model in the manifest, and derive the release event timestamp from Git creatordate so annotated and lightweight tags both produce stable dates.

Correctness: the archive remains deterministic and actions/upload-artifact retains the exact distributable; ngit signs its hash, size, MIME type, filename, URL, and Linux platform in the kind-3063 event.

Excluded: the already-published 3.0.1 release is not replaced, and truly multi-platform release layouts remain unchanged.

Validation: actionlint accepts the workflow; Git creatordate reproduces the v3.0.0 and v3.0.1 tag timestamps; ngit parses the manifest and reaches the expected publisher-author guard without signing or uploading.
2026-09-03 12:42:22 +00:00
DanConwayDev 4b2d7511e1 Merge #a52fa551: ci(release): publish NIP-82 releases from tags
nostr:nevent1qgsx2lyl2e4zvfadwcvkd9fkrcwczj7mf858hy85mwqclwgut8wpg2spz3mhxue69uhhyetvv9ujumn8d96zuer9wcq3yamnwvaz7tm8d96xummnw3ezucm0d5q3kamnwvaz7tmwva5hgtnyv9hxxmmwwashjer9wchxxmmdqqs22ta92yrt4cmtklv9k5luw6t576d3z4nd0tfqud3s6swdcfrcxjgrmf5tu

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

Motivation: make tagged ngit-grasp builds discoverable as complete NIP-82 releases without retaining the legacy zsp publication path.

Approach: commit the application and asset manifest, install ngit through setup-ngit v3, and publish with the established dcdev nbunksec after reproducible archive packaging.

Correctness: derive version and commit from the exact tag, enforce the expected application author and strict metadata, replicate to the pinned Primal, Ditto, and Haven Blossom servers, and publish to repository, catalog, and release relays.

Security: place the CI nbunksec in a mode-restricted temporary file and remove it on exit; no signing material is stored in the repository or process arguments.

Excluded: v3.0.1 predates this workflow and will be backfilled manually from its exact tag; automatic publication begins with the next genuine version tag.

Validation: actionlint accepted the workflow, and ngit parsed the manifest before stopping at the expected dcdev publisher guard without uploading or signing.
2026-09-03 13:23:24 +01:00
DanConwayDev 8bfed0224e ci(release): publish NIP-82 releases from tags
Motivation: make tagged ngit-grasp builds discoverable as complete NIP-82 releases without retaining the legacy zsp publication path.

Approach: commit the application and asset manifest, install ngit through setup-ngit v3, and publish with the established dcdev nbunksec after reproducible archive packaging.

Correctness: derive version and commit from the exact tag, enforce the expected application author and strict metadata, replicate to the pinned Primal, Ditto, and Haven Blossom servers, and publish to repository, catalog, and release relays.

Security: place the CI nbunksec in a mode-restricted temporary file and remove it on exit; no signing material is stored in the repository or process arguments.

Excluded: v3.0.1 predates this workflow and will be backfilled manually from its exact tag; automatic publication begins with the next genuine version tag.

Validation: actionlint accepted the workflow, and ngit parsed the manifest before stopping at the expected dcdev publisher guard without uploading or signing.
2026-09-03 12:11:56 +00:00
DanConwayDev 31c8473001 chore(release): prepare v3.0.1
Motivation: Publish the narrowly scoped maintainer-authority correction and its follow-up model clarification as the first v3 patch release.

Approach: Promote the pending changelog fix to 3.0.1, advance its comparison links, and align the Cargo and NixOS module package versions.

Correctness: Cargo metadata and the flake package both report 3.0.1. The NixOS module parses and its static package version matches.

Excluded scope: This commit does not create or push the v3.0.1 tag, publish release assets, change runtime behavior, or bump the independently versioned grasp-audit crate.

Validation: git diff --check; cargo metadata --locked; nix eval of the ngit-grasp package version; nix-instantiate --parse of nix/module.nix plus an exact module-version check. Tests were not rerun for this metadata-only change.
v3.0.1
2026-08-29 22:46:22 +00:00
DanConwayDev fd7c6bb851 refactor(auth): make current maintainer authority explicit
The v3.0.1 authorization fix is intentionally small. Follow it with a separate structural pass so the implementation and documentation express the present-tense maintainer model directly instead of leaving the security behavior hidden behind owner-oriented names and repeated raw-tag interpretation.

Parse indexed roles once into a current-only snapshot of active maintainers, active lead targets, and announcement-author activity. Preserve detailed lead-resolution failures internally while policy callers continue to fail closed, distinguish selected authorization coordinates from physical owner views, and name broad announcement admission as discovery rather than authority.

Keep history relevant only while deriving current activity and retain active leads only for selected-coordinate resolution. Preserve the v3.0 public API through compatibility projections and deprecated aliases; this commit is not intended to change the authorization outcome established by 650cfb57.

Refresh architecture, inline authorization, storage, sync, and audit documentation. Correct the audit fixture description that claimed a listed maintainer authorized with no reciprocal announcement even though its setup already published one.

Validated with cargo test --lib (903 tests), cargo test --test state_authorization (53 tests), cargo test -p grasp-audit --lib (54 passed, 5 ignored), cargo test --test push_authorization (56 tests), and cargo clippy --tests -- -D warnings.
2026-08-29 21:20:49 +00:00
DanConwayDev 650cfb57ee fix(auth): root state validity at active lead
The v3 role-tag work filtered invited and ended listed maintainers, but every announcement author still seeded a repository view. A removed forwarding maintainer or an author with an ended self-role could therefore keep publishing authoritative kind 30618 state through their own coordinate. Parity-only role parsing could also treat malformed histories as active.

Validate numeric role boundaries and the final-end-only defer sentinel, resolve each selected coordinate through one valid active M path to a terminal self-M, and only then seed the reciprocal membership fixpoint. Legacy and explicitly leadless views continue to root at the selected author while that author remains active; incomplete, ambiguous, and cyclic explicit paths fail closed.

This changes current state and maintainer-scoped authorization only. Historical event authorization and membership mutation workflows remain outside the relay-side patch.

Validated with cargo test --lib (902 tests), cargo test --test state_authorization (53 tests), and cargo clippy --tests -- -D warnings.
2026-08-29 20:18:22 +00:00
DanConwayDev c1ebbf1aae feat(cli): export deterministic documentation schema
Documentation builds need a source-owned view of ngit-grasp commands and runtime configuration without copying Clap help or operator defaults into another repository.

Add an early hidden __docs-export dispatch that serializes schema-v1 command metadata, deduplicated public environment options, runtime constraints, dotenv behavior, and relay-owner secret precedence. Clap remains authoritative for reflectable facts; a narrow explicit registry covers validation and the skipped secret.

Correctness assumes Config::validate relationships continue to be mirrored in the constraint registry when they change. Secret source metadata intentionally contains locations and precedence only, never loaded values.

This does not publish artifacts, generate ngit.dev pages, expose internal test switches, model conditional Clap requirements that stable reflection cannot expose, or change normal relay and maintenance-command behavior.

Validated with cargo fmt --check, targeted unit and startup-isolation integration tests, all-target/all-feature clippy with warnings denied, deterministic process-output comparison, and jq schema assertions.
2026-08-28 15:28:21 +00:00
DanConwayDev 3b8b74c22f fix(repo): remove accidentally tracked worktree gitlink
The v3.0.0 source tree accidentally recorded a local linked worktree as a mode-160000 Gitlink without a matching .gitmodules entry. Git and Nix fetchers consequently materialized the same revision with inconsistent directory shapes and NAR hashes.

Remove only the index entry. The existing /worktrees ignore rule keeps repository-local linked worktrees out of future commits, and the registered worktree plus its branch and files remain intact.

This does not change runtime code, release behavior, or the linked worktree contents. Validation: git diff --cached --check before commit and git worktree list after removal.
2026-08-22 09:31:57 +00:00
DanConwayDev bce30ef039 chore: prepare release 3.0.0
Motivation: The v3 storage, security, private-repository, and proactive-sync changes have completed production migration and integrity-check validation.

Approach: Promote the accumulated changelog entries to 3.0.0, polish the major-release summary, advance comparison links, and align Cargo plus the NixOS module package versions.

Correctness: Cargo metadata and both Nix package evaluations report 3.0.0, matching the version required by the tag-triggered release workflow.

Excluded scope: This commit does not create the v3.0.0 tag, publish release assets, change runtime behavior, or modify deployment pins.

Validation: git diff --check; cargo metadata --locked; nix eval for ngit-grasp and static package versions. No build or tests were run for this metadata-only change.
v3.0.0
2026-08-20 21:07:03 +00:00
DanConwayDev 8698c10102 Merge #66c9386e: Add portable deployment paths and managed hosting temp…
Add portable deployment paths and managed hosting templates

nostr:nevent1qqsxdjfcdmr88n4pe79h4st43kvkwzssekuwepmsl7dt3ze2x0a27scpz3mhxue69uhhyetvv9ujumn8d96zuer9wc5fxfyx

PR-Author: DanConwayDev's Agent
nostr:npub1v47f74n2ycn66asev62nv8sas99akj0g0wg0fkup37u3ckwuzs4q7cwtp0

PR description:

Define one durable single-writer deployment contract, then implement it with a non-root Docker image, Compose and Caddy, a generic systemd unit, and separate NixOS, Linux, and Proxmox guides.

Add Railway, Render, and Fly.io templates that share the same /data layout, plus bounded public verification and a container replacement test that proves the relay identity survives.

The dedicated container e2e workflow expects the ngit-ci KVM runner to opt in to exposing its disposable guest Docker socket; it fails clearly if that prerequisite is absent.
2026-08-20 20:52:21 +00:00
DanConwayDev b1c6147474 test(grasp06): recognize actual missing endpoints
The GRASP-06 rejection helper treated any 404 digits anywhere in git stderr as evidence that the smart-HTTP endpoint was absent. A randomly generated repository UUID containing 404b therefore turned a valid server-side ref rejection into a false test failure.

Match transport-specific Git missing-repository diagnostics and cover both the accepted phrases and the observed URL regression. This changes only audit classification; relay behavior and the GRASP-06 contract are deliberately unchanged.

Validated with the focused grasp-audit unit tests, cargo fmt --check, and the formerly failing grasp06_pr_hosting integration test against a spawned relay.
2026-08-20 20:16:47 +00:00
DanConwayDev 527bfeced5 docs(storage): distinguish legacy incomplete histories
Motivation: Production v3 rehearsal found unmarked missing ancestors that the previous shallow-fetch wording could misattribute to a narrow pre-release bug.

Approach: Describe incomplete legacy object graphs without inferring provenance, retain the shallow marker as a specific historical case, and document a minimal maintainer-bundle recovery procedure. Remove stale test comments claiming current purgatory fetches are shallow.

Correctness: Current fetches have no depth limit, migration logged the affected graphs as pre-existing, and an unmarked missing parent is not evidence of the marked January fallback behavior.

Excluded scope: No integrity policy, object import automation, migration behavior, or production data is changed.

Validation: Ran git diff --check and reviewed the production sweep evidence; tests were intentionally skipped because this commit changes documentation and comments only.
2026-08-20 20:16:32 +00:00
DanConwayDev 03d2b24bfe ci(deploy): exercise container replacement
The portable image and persistence test should run in CI rather than relying on an operator to have Docker installed locally.

Add a focused ngit-ci workflow that obtains only the Docker client, curl, and jq through Nix, then builds the image, replaces the relay container, and verifies that its NIP-11 identity survives on the mounted volume.

The workflow deliberately requires an explicitly mounted daemon socket and fails clearly when the operator has kept ngit-ci's secure default. This is intended for the disposable KVM guest daemon and does not weaken embedded-act hosts.

Validated the workflow as YAML and listed its jobs and triggers with act 0.2.86 or newer from the ngit-ci development shell; git diff --check passes. The actual container job requires the remote runner's opted-in guest socket.
2026-08-20 20:00:28 +00:00
DanConwayDev 22bbd48537 docs(deploy): add host-specific production paths
The production guide was NixOS-only despite presenting itself as the general deployment entry point, and its examples referenced an unavailable GitHub source and a hardening control the module does not set.

Turn the entry point into an environment chooser, preserve the corrected NixOS material in its own guide, add a hardened generic systemd unit and repeatable Linux installation, document the preferred unprivileged Proxmox layout, and update repository navigation and architecture references.

Each path assumes the shared deployment contract from the container change. Kubernetes automation, remote host mutation, and changes to the existing NixOS module are deliberately excluded.

Validated the canonical Git remote with git ls-remote, parsed and scored the systemd unit with systemd-analyze, checked all new deployment-guide links, removed trailing whitespace, scanned the staged diff for key-shaped nsec values, and ran git diff --check.
2026-08-20 19:38:04 +00:00
DanConwayDev 28c881ba97 feat(deploy): add managed hosting templates
Agents need repeatable provider inputs instead of translating a generic container guide into mutable dashboard settings on every deployment.

Add Railway, Render, and Fly.io configurations that all build the canonical Dockerfile, mount /data, expose one HTTP service, allow bounded shutdown, and avoid overlapping writers. Pair them with provider-specific CLI and dashboard instructions, DNS verification, backup cautions, and one-instance constraints.

The templates assume each provider terminates TLS and preserves WebSocket upgrades. Render still requires a supported connected Git source for Blueprint automation, and provider credentials or account mutations are deliberately outside this commit.

Validated Railway and Render against their current published JSON schemas, parsed both TOML files and all YAML, checked Fly fields against its current official reference, verified local documentation links, and ran git diff --check. flyctl strict validation was not possible without a Fly access token.
2026-08-20 19:38:04 +00:00
DanConwayDev 37d81f3713 feat(deploy): add portable container contract
Production deployment previously depended on an illustrative Docker snippet and did not define which state or identity must survive replacement.

Add a non-root runtime image, loopback-only Compose service, optional Caddy TLS overlay, shared /data layout, bounded public verifier, and an identity-persistence container test. Document backup, proxy, single-writer, upgrade, and rollback requirements as the contract for every environment.

This assumes one ngit-grasp writer per state directory and a reverse proxy or platform edge for public TLS. Image publication and provider-specific control-plane setup are deliberately left to separate changes.

Validated with sh -n, ShellCheck 0.11.0, locked Cargo metadata, YAML parsing, Docker Hub tag lookups, local input-failure checks, and git diff --check. Docker/Podman is unavailable in this VM, so the included end-to-end container test was not run here.
2026-08-20 19:38:04 +00:00
DanConwayDev 47bfc2015d docs(security): qualify GRASP-06 integrity warning
Motivation: The previous wording could imply that signed Nostr repository state or normal Nostr Git checkouts were themselves compromised.

Approach: Describe the concrete risk as unauthorized server-side objects or refs, while distinguishing conforming Nostr Git clients from direct Git consumers.

Correctness: The wording retains the full v3 integrity-pass requirement and does not weaken the separate unauthenticated-read disclosure.

Excluded scope: No runtime behavior, checker policy, or release procedure changes are included.

Validation: Reviewed both rendered Markdown sources and ran git diff --check.
2026-08-20 19:22:23 +00:00
DanConwayDev cbe48d9ce2 docs: define owner-view PR ref authority
Motivation:
The authorization-integrity implementation now recognizes exact standard clone endpoints as an alternative owner-view authority, but the v3 changelog and migration architecture still described only maintainer-overlap propagation.

Approach:
Document both accepted owner-view paths and explicitly state that foreign services, different coordinates, URL suffixes, and /prs/ endpoints do not satisfy the standard endpoint rule. Preserve the existing GRASP-06 warning and operator requirement to inspect manual findings.

Correctness assumptions:
The accepted event database remains authoritative and GRASP-06 contributor views continue to use their separate signer plus exact /prs/ coordinate predicate.

Excluded scope:
This changes no runtime behavior, deployment pin, release tag, or production repository data.

Validation:
git diff --check; review against the remotely built and production-validated 44a16da9 behavior.
2026-08-20 19:14:49 +00:00
DanConwayDev 44a16da91f fix(security): recognize exact owner clone endpoints
Motivation:
The authorization-integrity pass treated PR refs hosted in a submitter owner view as unexplained whenever the PR targeted a different repository owner. NIP-34 clone tags can legitimately name that submitter-hosted standard endpoint, producing false manual-inspection findings and obscuring actual unexplained refs.

Approach:
Authorize an owner-view PR ref when either the existing target-maintainer relationship applies or an HTTP(S) clone tag exactly names the canonical service mount, owner npub, and identifier. Include those source identifiers in the lease-time event refresh and reject foreign authorities, credentials, query/fragment suffixes, extra paths, different coordinates, and /prs/ endpoints.

Correctness assumptions:
Accepted PR and PR Update events remain the event authority. Exact clone URL ownership is an alternative location signal only for the named owner view; it does not weaken base-repository maintainer authorization or GRASP-06 /prs/ scoping.

Excluded scope:
This does not delete unresolved refs, repair malformed State HEAD tags, change storage migration, tag v3, or alter deployment configuration.

Validation:
cargo fmt --check; git diff --check. Compilation and production behavior will be validated through the required remote Nix deployments.
2026-08-20 18:54:25 +00:00
DanConwayDev 5d2ba5462e feat(security): support scoped integrity validation
Motivation:
Production release-candidate validation must be able to exercise the new storage and event-authorization checker on selected identifier families without immediately sweeping thousands of repositories. The existing manual command also covered storage only, which made its name and operator workflow misleading.

Approach:
Apply one validated startup identifier scope to both background passes, with an empty scope retaining the secure all-family default and unmatched names counted as failures. Extend durable manual requests so check-only mode compares refs without mutation and --repair applies the same safe authorization reconciliation after storage repair. Expose the scope consistently through CLI/env, the NixOS module, examples, operator docs, architecture notes, and the v3 security warning.

Correctness assumptions:
Accepted State, PR, and PR Update events remain authoritative, active precisely-scoped purgatory entries remain valid in-flight exceptions, and unexplained PR refs remain preserved for manual inspection. A scoped pass proves only the named identifiers; full v3 assurance still requires removing the scope and completing the default sweep.

Excluded scope:
This does not tag v3, alter migration behavior, update the production deployment, or delete unexplained refs. It also does not make the manual request synchronous; the live worker continues to consume durable requests.

Validation:
- cargo clippy --all-targets --locked -- -D warnings
- cargo test --lib --locked (895 passed)
- focused scoped-selection and non-mutating reconciliation tests
- resource-safe NixOS module evaluation of startupIntegrityIdentifiers
2026-08-20 07:57:57 +00:00
DanConwayDev cc5a3cbb0e fix(security): reconcile served refs with authorized events
Motivation: the v3 storage migration preserves legacy refs exactly, so structural Git integrity alone cannot detect refs written through the pre-v3 GRASP-06 path traversal. Operators need an online, post-migration answer without extending the production outage.

Approach: add a second startup pass that derives owner refs from the NIP-01-preferred State of the confirmed maintainer set and PR refs from accepted PR/PR Update events, including exact GRASP-06 and active-purgatory scoping. Fetch missing expected objects through the hardened repair path, repair unambiguous drift, and preserve unexplained refs with bounded manual-inspection logs.

Correctness: authoritative events are refreshed while holding the family lease, ref updates use compare-and-swap, and anything changed since the initial online snapshot is left untouched. This assumes the accepted event database and existing membership/GRASP-06 predicates are authoritative. The offline migration is deliberately unchanged, and unexplained PR refs are not auto-deleted because they may be evidence.

Validation: cargo fmt --all -- --check; cargo clippy --workspace --all-targets -- -D warnings; cargo test --locked; cargo test --lib --locked (892 passed after the final race guard).
2026-08-20 07:35:24 +00:00
DanConwayDev d281b83a2f docs: remove unsupported release publication guidance
The release checklist was requested as conversational guidance, and the checked-in version incorrectly treated an unauthorized GitHub repository as a project mirror.\n\nRemove the checklist and its index entries, along with the README claim that GitHub is a mirror. This assumes the Nostr-hosted repository remains sufficient for the current release; creating an authorized GitHub mirror is deliberately left for a separate decision.\n\nNo release tag, remote, package, container, deployment configuration, or in-progress v3 implementation is changed. Validation: git diff --cached --check and a scoped review of the staged documentation diff.
2026-08-20 07:25:46 +00:00
DanConwayDev d4f458c155 docs: add v3 release checklist
The release process spans canonical Nostr refs, ngit-ci artifacts, a stale GitHub mirror, an existing crates.io package, and native NixOS deployments, while the only public container belongs to the archived ngit-relay predecessor. Without one checklist it is easy to omit a live channel or publish into the wrong namespace.

Document release freezing, metadata synchronization, validation, immutable tag publication, artifact verification, GitHub reconciliation, the crates.io decision, production rollout, announcements, and rollback rules. Record the current mirror divergence and explicitly exclude Docker Hub and the archived GHCR image from the v3 release path.

The checklist assumes v3.0.0 remains the intended version, the canonical Nostr repository is authoritative, and production continues to consume the pinned NixOS module. It deliberately does not reconcile or push the GitHub mirror, publish any package, create a tag, add container packaging, or deploy production.

Validated with public GitHub, GHCR, Docker Hub, crates.io, and production-config inspection; a clean-worktree cargo publish dry run for ngit-grasp; staged markdown fence and relative-link checks; external link probes; and git diff --cached --check.
2026-08-20 07:21:45 +00:00
DanConwayDev 025004c918 docs: record maintainer authorization break
Version 3 changes maintainer authorization from unilateral listing to reciprocal membership and adds indexed NIP-34 role-tag parsing. Although the release-time authorization state of live repositories is unaffected, operators and clients need this called out before upgrading because future invitations require explicit acceptance and role tags supersede the legacy maintainers list.

Document the acceptance requirement, zero-live-repository impact, M/m/o semantics, and maintainers-tag fallback in Unreleased breaking changes. Also correct the existing invitation-sync entry so it no longer claims one-way authority before acceptance.

This assumes the reciprocal membership implementation, current architecture decision, and reported live-repository impact are authoritative. No runtime behavior or protocol parsing is changed.

Validation: git diff --cached --check
2026-08-20 07:15:30 +00:00
DanConwayDev a57347b3ce feat(release): build portable tagged archives
Tagged releases need installable artifacts whose source and embedded revision are pinned to the pushed tag, without requiring operators to have Rust or Nix on the deployment host.

Add a Linux pkgsStatic output and a v* ngit-ci workflow that verifies the tag against Cargo package metadata, builds the x86_64 MUSL binary, creates a reproducible licensed archive and SHA256SUMS, and uploads both as release assets. Derive the Nix package version from Cargo.toml so release validation has one authoritative version.

The first artifact target assumes x86_64 Linux and the existing tag-trigger environment provided by ngit-ci. Multi-architecture archives, OCI publication, release tagging, and the separate v3 metadata promotion are deliberately excluded.

Validated with a staged-tree nix build .#static, static PIE and embedded-revision inspection, an archive/checksum round trip, nix flake check --no-build --no-write-lock-file, cargo metadata, and git diff --check.
2026-08-20 07:00:02 +00:00
DanConwayDev 6c0c2187e0 docs: refresh supported GRASP profiles
The README stopped at GRASP-02, described implemented Sync+ and object deduplication as roadmap work, and still compared the service with the retired ngit-relay project. This made the project overview and operator-facing settings materially diverge from the current implementation.

Present GRASP-02 and default-on GRASP-03 as one sync system, document opt-in GRASP-08 behavior and settings, replace stale sync options from the current CLI configuration, and move implemented observability out of the roadmap. Remove ngit-relay references and link the canonical ngit and ngit-ci sister repositories.

The descriptions and defaults assume src/config.rs, NIP-11 construction, and the current architecture documents are authoritative. This is documentation-only and deliberately does not change protocol behavior or configuration defaults.

Validation: git diff --cached --check; target/debug/ngit-grasp serve --help; canonical sister-project URLs returned HTTP 200
2026-08-20 06:45:34 +00:00
DanConwayDev 2771ed861d docs: clarify Nostr contribution workflow
A generic mirror notice does not explicitly tell contributors where pull requests and issues are handled. Recast the banner as a canonical-repository notice and state that collaboration is tracked exclusively through ngit and Nostr at Git Workshop.

This wording assumes GitHub remains a mirror but is not an active issue or pull-request tracker. No repository configuration or contribution tooling is changed.

Validation: git diff --cached --check
2026-08-20 06:35:07 +00:00