diff options
| author | Fuwn <[email protected]> | 2026-02-28 04:52:17 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-28 04:52:17 -0800 |
| commit | bb02fa43e5776e3d7b95cb47f0594eb4bd7f907f (patch) | |
| tree | 9d2e2f49c2e0cb9e153ca266d10b9b610e38c771 | |
| parent | build(task): add multi-arch docker build targets (diff) | |
| download | plutia-test-bb02fa43e5776e3d7b95cb47f0594eb4bd7f907f.tar.xz plutia-test-bb02fa43e5776e3d7b95cb47f0594eb4bd7f907f.zip | |
docs: refine user-facing wording for clarity and consistency
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | Taskfile.yaml | 28 | ||||
| -rw-r--r-- | cmd/plutia/main.go | 16 | ||||
| -rw-r--r-- | internal/api/server.go | 28 | ||||
| -rw-r--r-- | internal/config/config.go | 10 |
5 files changed, 44 insertions, 44 deletions
@@ -10,8 +10,8 @@ Plutia is a deterministic, verifiable PLC mirror for `plc.directory` with signed - Deterministic canonical operation handling and signature-chain verification. - Signed Merkle checkpoints and DID inclusion proof API. - Corruption detection and restart-safe ingestion. -- High-density storage scaling around ~1.2KB/op in benchmarked runs. -- ~45x faster than naive replay in benchmarked runs. +- Measured storage in benchmarked runs is about 1.2 KB per operation. +- Benchmarked replay throughput is about 45x higher than naive replay in the same test setup. ## Trust Model @@ -54,7 +54,7 @@ docker build \ -t plutia:local . ``` -In a second terminal, generate the mirror signing key inside the running container: +In another terminal, generate the mirror signing key inside the running container: ```bash docker compose -f docker-compose.yml -f docker-compose.dev.yml exec plutia /app/plutia keygen --out=/var/lib/plutia/mirror.key diff --git a/Taskfile.yaml b/Taskfile.yaml index 9d6f6a7..585f3b0 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -5,14 +5,14 @@ vars: VERSION: sh: | if [ ! -f VERSION ]; then - echo "VERSION file is required" >&2 + echo "VERSION file is required. Create VERSION and run the task again." >&2 exit 1 fi tr -d '\r\n' < VERSION VERSION_TAG: sh: | if [ ! -f VERSION ]; then - echo "VERSION file is required" >&2 + echo "VERSION file is required. Create VERSION and run the task again." >&2 exit 1 fi v="$(tr -d '\r\n' < VERSION)" @@ -20,11 +20,11 @@ vars: COMMIT: sh: | if ! command -v git >/dev/null 2>&1; then - echo "git is required to compute build metadata" >&2 + echo "Git is required to compute build metadata." >&2 exit 1 fi if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - echo "git repository context is required" >&2 + echo "A Git repository context is required." >&2 exit 1 fi git rev-parse --short HEAD @@ -44,7 +44,7 @@ tasks: desc: Ensure git metadata is available for version injection. preconditions: - sh: command -v git >/dev/null 2>&1 - msg: git is required but was not found in PATH + msg: Git is required. Install Git and run the task again. - sh: git rev-parse --is-inside-work-tree >/dev/null 2>&1 msg: task must run from inside the plutia git repository cmds: @@ -124,7 +124,7 @@ tasks: if command -v staticcheck >/dev/null 2>&1; then staticcheck ./... else - echo "staticcheck not installed; skipping" + echo "staticcheck is not installed, so this step is skipped." fi verify:small: @@ -147,7 +147,7 @@ tasks: - | checkpoint_count="$(find ./tmp-test-data/checkpoints -maxdepth 1 -type f -name '*.json' ! -name '*.state.json' | wc -l | awk '{print $1}')" if [ "${checkpoint_count}" -lt 1 ]; then - echo "verify:small failed: no checkpoint files generated" >&2 + echo "verify:small failed: no checkpoint files were generated." >&2 exit 1 fi global_seq="$(awk '/replay complete at sequence/ {print $5}' ./tmp-test-data/verify-small.log | tail -n 1)" @@ -208,7 +208,7 @@ tasks: - | echo "verify:1m checkpoint timing metrics" if ! grep -q 'checkpoint_metrics' ./scale-test-data-1m/verify-1m.log; then - echo "verify:1m failed: no checkpoint metrics emitted" >&2 + echo "verify:1m failed: no checkpoint metrics were emitted." >&2 exit 1 fi grep 'checkpoint_metrics' ./scale-test-data-1m/verify-1m.log @@ -228,7 +228,7 @@ tasks: - | block_files="$(find ./scale-test-data-resolver/ops -maxdepth 1 -type f -name '*.zst' | wc -l | awk '{print $1}')" if [ "${block_files}" -ne 0 ]; then - echo "verify:resolver failed: expected zero block files, found ${block_files}" >&2 + echo "verify:resolver failed: expected zero block files, found ${block_files}." >&2 exit 1 fi echo "verify:resolver summary" @@ -258,17 +258,17 @@ tasks: - | block_file="$(find ./tmp-test-data-corruption/ops -maxdepth 1 -type f -name '*.zst' | sort | head -n 1)" if [ -z "${block_file}" ]; then - echo "verify:corruption failed: no block file was created" >&2 + echo "verify:corruption failed: no block file was created." >&2 exit 1 fi printf 'tamper' >> "${block_file}" - | if {{.BIN}} replay --config=config.default.yaml --max-ops=5000 > ./tmp-test-data-corruption/restart.log 2>&1; then - echo "verify:corruption failed: replay succeeded after tampering" >&2 + echo "verify:corruption failed: replay succeeded after tampering." >&2 exit 1 fi if ! grep -qi 'corruption' ./tmp-test-data-corruption/restart.log; then - echo "verify:corruption failed: corruption was not reported" >&2 + echo "verify:corruption failed: corruption was not reported." >&2 cat ./tmp-test-data-corruption/restart.log exit 1 fi @@ -330,8 +330,8 @@ tasks: - sh: docker buildx version >/dev/null 2>&1 msg: docker buildx is required for multi-architecture docker:build cmds: - - docker buildx build --platform linux/amd64 -t ghcr.io/fuwn/plutia:{{.VERSION_TAG}}-amd64 --load . - - docker buildx build --platform linux/arm64 -t ghcr.io/fuwn/plutia:{{.VERSION_TAG}}-arm64 --load . + - docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/fuwn/plutia:{{.VERSION_TAG}} --push . + - docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/fuwn/plutia:latest --push . docker:run: desc: Run Plutia container with mounted config and persistent data. diff --git a/cmd/plutia/main.go b/cmd/plutia/main.go index b6192f5..a3e8567 100644 --- a/cmd/plutia/main.go +++ b/cmd/plutia/main.go @@ -88,7 +88,7 @@ func main() { func runServe(args []string) error { fs := flag.NewFlagSet("serve", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") + configPath := fs.String("config", "config.default.yaml", "path to config file") maxOps := fs.Uint64("max-ops", 0, "max operations to ingest in this process (0 = unlimited)") if err := fs.Parse(args); err != nil { @@ -175,7 +175,7 @@ func runServe(args []string) error { func runReplay(args []string) error { fs := flag.NewFlagSet("replay", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") + configPath := fs.String("config", "config.default.yaml", "path to config file") maxOps := fs.Uint64("max-ops", 0, "max operations to ingest in this process (0 = unlimited)") if err := fs.Parse(args); err != nil { @@ -212,8 +212,8 @@ func runReplay(args []string) error { func runVerify(args []string) error { fs := flag.NewFlagSet("verify", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") - did := fs.String("did", "", "did to verify") + configPath := fs.String("config", "config.default.yaml", "path to config file") + did := fs.String("did", "", "DID to verify") if err := fs.Parse(args); err != nil { return err @@ -243,7 +243,7 @@ func runVerify(args []string) error { func runSnapshot(args []string) error { fs := flag.NewFlagSet("snapshot", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") + configPath := fs.String("config", "config.default.yaml", "path to config file") if err := fs.Parse(args); err != nil { return err @@ -271,7 +271,7 @@ func runSnapshot(args []string) error { func runBench(args []string) error { fs := flag.NewFlagSet("bench", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") + configPath := fs.String("config", "config.default.yaml", "path to config file") maxOps := fs.Uint64("max-ops", 200000, "max operations to ingest for benchmark") interval := fs.Duration("interval", 10*time.Second, "rolling report interval") @@ -365,8 +365,8 @@ func runBench(args []string) error { func runCompare(args []string) error { fs := flag.NewFlagSet("compare", flag.ExitOnError) - configPath := fs.String("config", "config.default.yaml", "config path") - remote := fs.String("remote", "", "remote mirror base URL") + configPath := fs.String("config", "config.default.yaml", "path to config file") + remote := fs.String("remote", "", "base URL for remote mirror") if err := fs.Parse(args); err != nil { return err diff --git a/internal/api/server.go b/internal/api/server.go index a3b4513..158a6fe 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -137,7 +137,7 @@ func (s *Server) handleLatestCheckpoint(w http.ResponseWriter, r *http.Request) } if !ok { - writeErr(w, http.StatusNotFound, fmt.Errorf("no checkpoint available")) + writeErr(w, http.StatusNotFound, fmt.Errorf("No checkpoint is available.")) return } @@ -149,7 +149,7 @@ func (s *Server) handleCheckpointBySequence(w http.ResponseWriter, r *http.Reque path := strings.TrimPrefix(r.URL.Path, "/checkpoints/") if path == "" { - writeErr(w, http.StatusNotFound, fmt.Errorf("missing checkpoint sequence in request path")) + writeErr(w, http.StatusNotFound, fmt.Errorf("Missing checkpoint sequence in request path.")) return } @@ -157,7 +157,7 @@ func (s *Server) handleCheckpointBySequence(w http.ResponseWriter, r *http.Reque seq, err := strconv.ParseUint(path, 10, 64) if err != nil { - writeErr(w, http.StatusBadRequest, fmt.Errorf("invalid checkpoint sequence")) + writeErr(w, http.StatusBadRequest, fmt.Errorf("Invalid checkpoint sequence.")) return } @@ -171,7 +171,7 @@ func (s *Server) handleCheckpointBySequence(w http.ResponseWriter, r *http.Reque } if !ok { - writeErr(w, http.StatusNotFound, fmt.Errorf("checkpoint not found")) + writeErr(w, http.StatusNotFound, fmt.Errorf("Checkpoint not found.")) return } @@ -183,7 +183,7 @@ func (s *Server) handleDID(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/did/") if path == "" { - writeErr(w, http.StatusBadRequest, fmt.Errorf("missing DID in request path")) + writeErr(w, http.StatusBadRequest, fmt.Errorf("Missing DID in request path.")) return } @@ -192,7 +192,7 @@ func (s *Server) handleDID(w http.ResponseWriter, r *http.Request) { did := strings.TrimSuffix(path, "/proof") if !s.allowRequest(r, limiterProof) { - writeErr(w, http.StatusTooManyRequests, fmt.Errorf("too many proof requests. Try again later.")) + writeErr(w, http.StatusTooManyRequests, fmt.Errorf("Too many proof requests. Try again later.")) return } @@ -203,7 +203,7 @@ func (s *Server) handleDID(w http.ResponseWriter, r *http.Request) { } if !s.allowRequest(r, limiterResolve) { - writeErr(w, http.StatusTooManyRequests, fmt.Errorf("too many resolve requests. Try again later.")) + writeErr(w, http.StatusTooManyRequests, fmt.Errorf("Too many resolve requests. Try again later.")) return } @@ -217,7 +217,7 @@ func (s *Server) handleDIDResolve(w http.ResponseWriter, r *http.Request, did st resolvedState, err := s.ingestor.ResolveState(r.Context(), did) if err != nil { if errors.Is(err, ingest.ErrDIDNotFound) { - writeErr(w, http.StatusNotFound, fmt.Errorf("DID not found")) + writeErr(w, http.StatusNotFound, fmt.Errorf("DID not found.")) return } @@ -243,7 +243,7 @@ func (s *Server) handleDIDResolve(w http.ResponseWriter, r *http.Request, did st } if !ok { - writeErr(w, http.StatusNotFound, fmt.Errorf("DID not found")) + writeErr(w, http.StatusNotFound, fmt.Errorf("DID not found.")) return } @@ -277,13 +277,13 @@ func (s *Server) handleDIDResolve(w http.ResponseWriter, r *http.Request, did st func (s *Server) handleDIDProof(w http.ResponseWriter, r *http.Request, did string) { if s.cfg.Mode == config.ModeThin { - writeErr(w, http.StatusNotImplemented, fmt.Errorf("thin mode does not support checkpoint proofs")) + writeErr(w, http.StatusNotImplemented, fmt.Errorf("Thin mode does not support checkpoint proofs.")) return } if s.ingestor == nil { - writeErr(w, http.StatusServiceUnavailable, fmt.Errorf("service unavailable")) + writeErr(w, http.StatusServiceUnavailable, fmt.Errorf("Service unavailable.")) return } @@ -331,7 +331,7 @@ func (s *Server) handleDIDProof(w http.ResponseWriter, r *http.Request, did stri } if !found { - writeErr(w, http.StatusNotFound, fmt.Errorf("DID is not present in the checkpoint state")) + writeErr(w, http.StatusNotFound, fmt.Errorf("DID is not present in the checkpoint state.")) return } @@ -1016,7 +1016,7 @@ func (s *Server) selectCheckpointForProof(r *http.Request) (types.CheckpointV1, } if !ok { - return types.CheckpointV1{}, nil, fmt.Errorf("no checkpoint available") + return types.CheckpointV1{}, nil, fmt.Errorf("No checkpoint is available.") } return cp, func() error { @@ -1041,7 +1041,7 @@ func (s *Server) selectCheckpointForProof(r *http.Request) (types.CheckpointV1, seq, err := strconv.ParseUint(checkpointParam, 10, 64) if err != nil { - return types.CheckpointV1{}, nil, fmt.Errorf("invalid checkpoint query parameter") + return types.CheckpointV1{}, nil, fmt.Errorf("Invalid checkpoint query parameter.") } cp, ok, err := s.store.GetCheckpoint(seq) diff --git a/internal/config/config.go b/internal/config/config.go index e94b5ea..69173fd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -176,21 +176,21 @@ func applyEnv(cfg *Config) { func (c Config) Validate() error { if c.Mode != ModeResolver && c.Mode != ModeMirror && c.Mode != ModeThin { - return fmt.Errorf("invalid mode %q", c.Mode) + return fmt.Errorf("mode must be one of mirror, resolver, or thin (got %q)", c.Mode) } switch c.VerifyPolicy { case VerifyFull, VerifyLazy, VerifyStateOnly: default: - return fmt.Errorf("invalid verify policy %q", c.VerifyPolicy) + return fmt.Errorf("verify must be one of full, lazy, or state-only (got %q)", c.VerifyPolicy) } if c.DataDir == "" { - return errors.New("data_dir is required") + return errors.New("set data_dir in the config file") } if c.PLCSource == "" { - return errors.New("plc_source is required") + return errors.New("set plc_source in the config file") } if c.ZstdLevel < 1 || c.ZstdLevel > 22 { @@ -226,7 +226,7 @@ func (c Config) Validate() error { } if c.ListenAddr == "" { - return errors.New("listen_addr is required") + return errors.New("set listen_addr in the config file") } if c.PollInterval <= 0 { |