feat(engine): parse and coerce MinerGoalSpec from raw config#2652
Conversation
Add a pure parser for .gittensory-miner.yml JSON with safe defaults, warnings, and deep-frozen output as the JSONbored#2293 follow-up module. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-03 05:33:37 UTC
⏸️ Suggested Action - Manual Review Review summary Nits — 6 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
JSONbored#2294) Layers the file-content and discovery parts of JSONbored#2294 on top of JSONbored#2652's already-merged parseMinerGoalSpec(raw) (raw-object validation/coercion), rather than duplicating it. - miner-goal-spec-parse.ts gains: - parseMinerGoalSpecContent(content, source?): YAML-then-JSON decode (looks-like-JSON → JSON.parse, else yaml.parse) that delegates to parseMinerGoalSpec, returning the same MinerGoalSpecParseResult. Never throws: empty/missing → defaults (present:false); an over-large (>64 KiB) file or invalid syntax → defaults + a source-aware warning. - MINER_GOAL_SPEC_FILENAMES discovery order (.gittensory-miner.yml → .github/… → .json variants) + pure discoverMinerGoalSpecPath(exists). - Adds the `yaml` dependency. Exposed via the existing ./miner-goal-spec-parse subpath. - .gittensory-miner.yml.example at repo root (matching .gittensory.yml.example style). The `gittensory-miner status` wiring stays deferred: that CLI command does not exist yet (the package ships a stub dispatcher); the parser + discovery are ready for it to consume. Tests (new content layer only; raw parser already covered by miner-goal-spec-parse.test.ts): missing/empty → defaults; YAML + JSON decode + delegate; invalid YAML/JSON → source-aware warning; over-large ignored; discovery order. Engine package: 29/29 pass.
…SONbored#2294) The tolerant parser (parseMinerGoalSpec / parseMinerGoalSpecContent) landed via JSONbored#2652/JSONbored#2658; this adds the remaining JSONbored#2294 pieces that were still missing on main: - discoverMinerGoalSpecPath(exists) + MINER_GOAL_SPEC_FILENAMES in miner-goal-spec.ts: the documented discovery order (.gittensory-miner.yml → .github/… → .json variants, first match wins). Pure — the existence check is injected, so it stays IO-free; a caller reads the returned path and feeds it to parseMinerGoalSpecContent. Exported from the barrel. - .gittensory-miner.yml.example at the repo root, matching .gittensory.yml.example's header + per-field "Default: X" style. Tests: discovery order, first-match-wins, null when absent, and that only the listed candidates are probed. Engine package: 37/37 pass.
…2294) (#2685) * feat(miner-foundation): MinerGoalSpec file discovery + example doc (#2294) The tolerant parser (parseMinerGoalSpec / parseMinerGoalSpecContent) landed via #2652/#2658; this adds the remaining #2294 pieces that were still missing on main: - discoverMinerGoalSpecPath(exists) + MINER_GOAL_SPEC_FILENAMES in miner-goal-spec.ts: the documented discovery order (.gittensory-miner.yml → .github/… → .json variants, first match wins). Pure — the existence check is injected, so it stays IO-free; a caller reads the returned path and feeds it to parseMinerGoalSpecContent. Exported from the barrel. - .gittensory-miner.yml.example at the repo root, matching .gittensory.yml.example's header + per-field "Default: X" style. Tests: discovery order, first-match-wins, null when absent, and that only the listed candidates are probed. Engine package: 37/37 pass. * refactor(miner-foundation): assert discovery short-circuit + ASCII-only example (#2294) - Add a probe-recording test that discoverMinerGoalSpecPath stops after the first match (.github yml), asserting the later .json variants are never probed — so a regression that keeps probing would be caught. - Replace the Unicode arrows/em-dashes in .gittensory-miner.yml.example with ASCII (-> and -) for copy/paste-friendly, diff-friendly config docs. Engine package: 38/38 pass. --------- Co-authored-by: Nick M <274344962+nickmopen@users.noreply.github.com> Co-authored-by: ghost <49853598+JSONbored@users.noreply.github.com>
…d duplicate parser (#4318) Two independently-filed issues (#2652's follow-up to #2293, and #2301) both specified a MinerGoalSpec parser. Two implementations landed around the same time: miner-goal-spec.ts became canonical (re-exported from the package barrel, the only one packages/gittensory-miner's real caller actually imports), while miner-goal-spec-parse.ts's own PR explicitly avoided the barrel "while #2628 is open" as a temporary conflict-avoidance measure that was never reconciled -- it sat published as its own npm subpath export with zero real callers anywhere in the repo. More importantly: the canonical file has the exact resource-exhaustion bug that #2896 patched in its orphaned sibling and nowhere else. normalizeStringList's cap check only fired after a candidate was accepted, so an array of entries that always take the `continue` path (non-string, duplicate, or empty-after-trim) never hit the cap and got scanned in full -- a hostile `.gittensory-miner.yml` with thousands of duplicate/invalid list entries could force unbounded CPU/memory work and unbounded warning growth on every repo a miner considers, since this parser runs on untrusted per-repo config. - Bound normalizeStringList's iteration to the raw array index, before any per-entry work, mirroring #2896's fix -- but WITHOUT that fix's own latent bug: a trailing `result.length >= cap` break (kept for "defense in depth") fires silently, with no warning, whenever the input has exactly cap+1 unique valid entries. A pre-existing test ("caps oversized string lists and ignores extra entries") caught this regression during review. The index-based check alone is both necessary and sufficient to bound work; the trailing check is removed rather than mirrored. - Delete the orphaned miner-goal-spec-parse.ts and its dedicated test (confirmed zero real callers, in-repo or via its published subpath). - Remove the ./miner-goal-spec-parse subpath from package.json's exports map. BREAKING CHANGE: @jsonbored/gittensory-engine's published subpath export is removed. The package is one week old with a single in-repo consumer that never used this subpath; no known external impact. - Add hostile-input regression tests (all-non-string, all-duplicate, all-empty, all-overlong) to both the package-level and root-level test suites for the canonical parser, mirroring the coverage #2896 added for its now-deleted sibling.
Summary
parseMinerGoalSpec()— the feat(miner-foundation): MinerGoalSpec type definitions for .gittensory-miner.yml #2293 follow-up parser for.gittensory-miner.ymlraw JSON.maxConcurrentClaims, and case-insensitiveissueDiscoveryPolicywith warnings on malformed input.@jsonbored/gittensory-engine/miner-goal-spec-parsesubpath (avoidsindex.tswhile feat(miner-plan): add analyze and prepare plan-DAG templates to the shared engine #2628 is open).Scope
packages/gittensory-engine/addition with node:test coverage.Validation
npm run build && npx tsc -p tsconfig.test.json && node --test dist-test/miner-goal-spec-parse.test.js— 4/4 passingSafety