mirror of
https://github.com/Heretek-AI/IUMBTEMS.git
synced 2026-10-11 21:09:53 +00:00
* M0 spike: prove OpenCode v2 extension points against a real in-process host 17/17 green against published @opencode/sdk 2.0.24 with a scripted fake model: tool.execute.before blocking (plugin + host-native tools, Effect and Promise APIs), permission.evaluate deny, per-agent wildcard-deny hiding of tools/MCP tools/skills, hidden subagents + depth limit, websearch/command/compaction/context/shell hooks, question forms, lsp passthrough, and a TUI session.panel rendered headlessly. Also records Pi 1.0.4 extension signatures and the Antigravity hooks contract, which refutes the plan's inferred hooks.json defect. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Start 1.0 monorepo: remove legacy tree, add es-core utilities Legacy Python runner and JS plugins are removed on the rewrite branch (preserved at tag legacy-final). Adds the Bun workspace scaffold and es-core foundations: canonical hashing, atomic writes with a crash-safe lock, portable globs, JSONC, a strict YAML-subset frontmatter parser, and a subprocess runner with timeouts, output caps, scrubbed env and a bwrap tmp-overlay read-only mode. 17 tests green. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M1: Factory state machine, mechanical gates, trust engine, and OpenCode v2 plugin Complete Milestone 1 of the IUMBTEMS 1.0 rewrite on branch rewrite: - Canonical Zod schemas (frontier, goal, phase, gates, waiver, approval, audit) - Cryptographic hash-chained JSONL audit logger and integrity verifier - Per-seat path write permissions (manager, programmer, qa-a, qa-b), control file protection, and STOP kill-file monitor - Mechanical gates engine with manifest auto-detect, secret scanner, budget checks, and waiver evaluation - Git worktree runner for phase isolation under .factory/worktrees/phase-<id> - Factory state machine with code-enforced transitions, retry policy, and autonomy caps - Promoted @heretek-ai/es-testkit from spikes/m0 for real in-process OpenCode testing - OpenCode v2 Promise plugin (@heretek-ai/epistemic-swarm) with tools, hooks, and commands - CLI runner (es-factory) and coarse stdio MCP server (@heretek-ai/es-cli) - 42/42 tests pass across 9 test suites; bun run check clean. * M1 remediation: canonical path policy, seat registry and control baseline Replaces the seat permission check that every agent bypassed. Paths are canonicalised (resolve, normalise, realpath of the existing prefix) before policy runs, so absolute paths, '..' segments and symlinks into .factory are caught. Control files are deny-write for every agent (config controls ask for non-seat agents), seats are looked up from a canonical agent registry by agent ID, the programmer may only write inside its phase worktree, QA is read-only, and the user-global state dir (signing key, trust store) is off limits. Adds the shell policy (human-only CLIs, control-file mentions, read-only seats via bwrap or an allowlist) and a control-file hash baseline. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M1 remediation: human-only signed approvals and a rewritten factory state machine Approvals: the subject is derived from the factory layout (never a caller- supplied path), validated, hashed and HMAC-signed with a key in the user-global state dir; records carry channel, OS user and the audit head. verifyApproval re-hashes the artifacts, so a spec edited after approval blocks the build and a hand-written record is rejected. Factory: GRILL → RESEARCH → SPEC → BUILD ⇄ QA → RELEASE → DONE (+ HALTED). Seat checks by agent ID; gates run in the phase worktree; complete requires changes, a recorded red test run, acceptance criteria and green gates; QA verdicts only from QA seats, tiebreak only from the manager; failure policy 3 + replan + 2 = halt on the 5th failure; passing phases fast-forward a run integration branch; release runs gates on it and opens a PR (DONE needs the URL). Every op checks STOP, control-file drift, spend and the runtime cap (counted from autonomy start). Side effects are journaled; state and audit move under .factory/runtime/, and approval anchors detect log truncation. The OpenCode plugin and CLI still target the old API and are reworked next. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M1 remediation: gates engine with trust pinning, parsed findings and logs - Commands come from .factory/gates.json or manifest detection (JS/TS, Python, Rust, Go), all in check mode; typecheck only when a tsconfig exists. - Fail closed: an untrusted command set never runs (hash of commands plus the package scripts they reach, approved by a human in the user-global trust store); missing tools, invalid gates.json and unreachable OSV on a dependency change are findings. - Findings are file:line:rule with fix hints, parsed from tsc, biome, eslint, prettier, ruff, mypy, cargo, gofmt, go vet and bun/vitest/jest/pytest/go/cargo test output; every command log and a full summary land in .factory/runs/<run>/gates/<stamp>/. - Touched scope runs runner-native related tests; full scope diffs against a base. Built-ins: secret scanner + gitleaks, OSV (osv-scanner or API), budgets (diff size, file length, complexity, dependency justification, test with behaviour change), artifact schemas, control drift, and tool-config edits inside a factory phase. - Waivers are HMAC-signed and expiring; forged ones are ignored and reported. - Phase worktrees get node_modules/.venv symlinks so tools resolve there. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M1 remediation: OpenCode v2 plugin rebuilt on the core policy, with a human-only TUI - Agents: the canonical registry compiles to v2 agents (factory, grill primaries; hidden manager/programmer/QA/research seats) with versioned markdown prompts, model tiers and wildcard-deny scoping of es_* tools, subagents, skills and MCP servers. Built-in agents are never modified; their es_* tool view is trimmed per request by the context hook. - Tools (direct, one permission action each): status, frontier write, approval *request*, research complete, spec validate, build start, gates, gated complete, QA verdict, tiebreak, replan, release. There is no approve tool. - Hooks: write/edit/patch/read/shell pass through the canonical-path policy; read-only seats run shells under bwrap (or allowlist + post-run diff check that halts); STOP and a halted run stop seats and es tools; autonomous seats never wait on an 'ask'; programmer edits get fast gate feedback; the factory state block is injected for factory agents and kept on compaction; spend accrues from step costs (estimated from tokens when 0). - Human channel: an RPC contract the TUI calls after a confirm dialog; every mutation redeems a short-lived preview token over the same subject. The TUI adds /es-approve, /es-trust, /es-resume and /es-status. - Real-host tests (published @opencode/sdk 2.0.24, fake model) cover the attacks from the review and a full grill → release run. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M1 remediation: es CLI with TTY-gated human actions, real MCP server, headless driver - Tool logic moves to a harness-neutral core module (esTools) used by the OpenCode plugin and the MCP server, and by the coming Claude/Pi/Antigravity adapters. - es CLI: status; factory begin/stop/resume/pr/run --headless; approve, trust, waive and resume require an interactive terminal and a typed random code, and show exactly what is signed; gates run (touched/staged/full, JSON) and an opt-in git hook installer (core.hooksPath); audit verify; mcp. - MCP: newline-delimited JSON-RPC over stdio (initialize, ping, tools/list, tools/call) with no approve/trust/waive/resume tool; caller identity is an advisory agent argument (or ES_AGENT). - Headless: driver interface plus an `opencode run --standalone --format json` driver; the loop stops for the grill, pending approvals, halts and stalls instead of guessing. - Policy: es factory resume/pr and gates install-git are human-only CLIs; .factory/git-hooks is a control path. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M2: hook bridge — Claude Code hooks running inside OpenCode v2 Core (harness-neutral, packages/core/src/hooks): - Canonical spec = Claude Code's hooks JSON schema (validated, unknown keys kept) plus namespaced extras: "x-es-policy": gate|observer and the "x-es.ShellPreExec" event. - Loading follows Claude's merge rules (.opencode/hooks.json, .claude/settings{,.local}.json, user configs; identical handlers run once; disableAllHooks). Project hooks are hash-pinned and run only after a human trusts them (shared trust dialog with gate commands). - Matchers: Claude exact-list/regex semantics against both the Claude and host-native tool names; `if` permission rules over Bash subcommands (including $() and backticks) and file paths. - Runner: command (exec/shell form, stdin JSON, exit-2 and JSON output rules), http, and prompt hooks via the host's model; mcp_tool/agent reported as capability loss. - Engine: parallel handlers; deny > defer > ask > allow; merged input edits and context; gates fail closed (error, timeout, missing trust), observers fail open; every run audit-logged; mtime reload; per-harness capability table and capability-loss report. OpenCode wiring: PreToolUse/PostToolUse(Failure) on tool hooks (deny, updatedInput, ask via the host prompt), UserPromptSubmit on prompt admission (block rejects), SessionStart (startup and after compaction), PermissionRequest on permission.evaluate, x-es.ShellPreExec on shell.create.before, and Stop emulated on execution end with an 8-continuation cap (advisory for plain chat). The factory session also auto-continues while work remains (stall- capped). /hooks and `es hooks` show status, trust and capability loss. Real-host tests cover each event, trust gating and fail-closed gates. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M3: LSP runtime for OpenCode v2 (which accepts but does not run the lsp key) Core (packages/core/src/lsp): - Registry of built-in servers (TypeScript, pyright, gopls, rust-analyzer, clangd) merged with OpenCode's own `lsp` config key (command, extensions, env, initialization, disabled; lsp:false turns it off), read from the same opencode.json(c) files, since plugins get no config API. - TypeScript resolves to the workspace's native `tsc --lsp --stdio` for TypeScript >= 7, else typescript-language-server; binaries come from the workspace node_modules, PATH, or a pinned install. - Ask-once installs: a human consents (es lsp install / TUI), the exact npm tarball's sha512 must match the pin, and it installs with scripts disabled into the user state dir. Agents cannot install (human-only CLI). - Client on vscode-jsonrpc: full document sync, push + pull diagnostics with a debounced settle, definition/references/hover/symbols/rename. - Manager: lazy start per (server, root) (phase worktrees get their own), idle shutdown, concurrency cap with LRU eviction. Surfaces: post-edit diagnostics appended to write/edit/patch results; lsp_diagnostics/definition/references/hover/symbols tools ("lsp" permission) and lsp_rename ("lsp_rename"; applying passes the write policy per file); per-agent access from the registry (programmer full, QA/manager/factory read, grill/research none); a touched-scope "lsp" gate in the engine; /lsp and `es lsp` status/diagnostics/install. Tested against real servers (native tsc --lsp, gopls) in core and on the real OpenCode host. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M4: research stack — cited, cached, audited evidence - Content-addressed source cache (.factory/research/sources/<sha256>.md + .json, URL index): tracked next to the report so reviewers can verify citations; tampered sources (bytes no longer matching the name) are refused; uncited sources are pruned when research completes. - Pure verbatim-quote verifier: whitespace/typography/markdown-normalised exact match, ellipsis fragments in order, minimum length; no fuzzy matching. - Epistemic auditor: every claim line needs a tag; [VERIFIED: sha256:<hash> "quote"] must quote the cached source verbatim; INFERRED/HYPOTHESIS/ NEGATIVE_KNOWLEDGE need substance; pruning moves failing claims to a 'Pruned claims' section; coverage report with counts only (no composite score). Enforced on research artifacts only (REPORT.md in the artifacts gate). - Providers: Brave, Firecrawl, SearXNG (env-configured) and a plain page fetcher with a dependency-free HTML-to-text converter. DDG scraping dropped. - The configured provider registers as the host websearch (results cached; default only when none is selected) and host webfetch results are cached too. - Research seats get es_research_search/fetch/audit; the factory's es_research_complete refuses a report that does not pass the audit and writes coverage.json. Prompts v2 for factory/research seats. `es research` CLI. Co-Authored-By: Claude Opus 5.5 <[email protected]> * M5: shared tree-sitter structural index; import-graph affected tests - Pinned grammars (typescript/tsx/javascript/python/go): each wasm comes from an exact npm tarball, verified against its SRI integrity and per-file sha256 before it is cached (user cache dir) and loaded; a tampered cache entry is refused and a network failure latches for 10 minutes; offline/ES_GRAMMARS=off falls back to the regex scanner. - Structural extraction: imports (static/type/dynamic/require/reexport/ side-effect) and top-level symbols per language, with a conservative regex fallback when grammars are unavailable. - Import graph: relative and workspace resolution for JS/TS ('.js' -> '.ts', index files, package.json exports including './*'), Python relative and absolute modules, and Go module paths (walking up to the nearest go.mod), plus reverse reachability for affected tests. - The gates engine prefers graph-derived affected tests for touched scope (language-filtered per runner; runner-native selection stays the fallback), so touched-scope test selection no longer guesses by file-name stem alone. - structure tests (grams pins, untar, cache integrity/offline, extraction, graph, caps) and gates integration tests. 170 tests green. * M5: brainstorm — divergent lenses, mechanical dedupe, rubric, diversified shortlist - Eight built-in lenses (inversion, constraint-removal, scamper, cross-domain, extreme-user, scale-shift, failure-first, adjacent-possible), each run by a hidden fast-tier subagent (es-lens-<id>); a visible primary 'brainstormer' orchestrates and a hidden deep-tier 'es-brainstorm-critic' scores. - es_brainstorm_plan freezes the lens set and the caps (6 lenses default, 5 ideas each, 600 chars) and returns the subagents to launch; es_brainstorm_ record enforces caps and collapses near-duplicates (word-bigram Jaccard); es_brainstorm_score is critic-only and validates 1-5 on the rubric (novelty, upside, feasibility, fit); es_brainstorm_complete refuses gaps and unscored survivors, ranks, and selects the diversified shortlist with a forced outlier slot, writing brainstorm.json + BRAINSTORM.md under .factory/brainstorm/. - Seat-scoped writes ('brainstorm' scope), /brainstorm command, es brainstorm plan|show|lenses in the CLI, per-agent model overrides (models.agents). - 13 core tests + 3 real-host tests (186 total green). * M5: darkharvest — fail-closed SPDX, provenance, policy-enforced matrix, clean-room specs - Deterministic SPDX detection from local bytes (signature phrases over LICENSE/COPYING files, then SPDX headers, then manifest claims marked unverified); AGPL/GPL/LGPL/MPL are classified as copyleft and unknown stays unknown. detectLicense never guesses. - Sources: GitHub/GitLab discovery APIs (injectable fetch, token-aware), a shallow clone, local directories and npm/PyPI/crates metadata; API licence fields are recorded as unverified claims. - es_harvest_scan builds a profile (languages, size, dependency graph from the shared tree-sitter index, commit, licence) with per-field provenance and warnings; es_harvest_read enforces a per-candidate token budget and refuses paths outside the candidate; failed scans are refusals, not silent gaps. - es_harvest_matrix applies the licence policy: depend/vendor require a text-verified, whitelisted licence, everything else is downgraded to clean-room with the reason, and allowed cells get SPDX attribution. es_harvest_complete writes harvest.json, HARVEST.md, VENDOR-PLAN.md and one clean-room spec per rebuild cell under .factory/harvest/. - es_harvest_prior_art feeds brainstorm's optional prior-art check (relations remain the LLM's judgement; failed searches are UNVERIFIED). - Visible 'harvester' primary seat, 'harvest' write scope, /harvest command, es harvest show|scan in the CLI. 14 core tests + 3 real-host tests (203 total green). * M6a: CI (check + docs drift) and nightly against OpenCode v2 HEAD - Spike (spikes/m6/RESULTS.md): v2 lives on anomalyco/opencode refs/heads/v2 (the default/dev branch is the v1 line); sdk/plugin export TS directly, so a shallow clone + bun install + node_modules relink runs our real-host suite against HEAD with no build. 34/34 packages/opencode tests pass against v2 HEAD 369aad3; cold end-to-end 29s. - scripts/v2-head.sh: clone/fetch v2 HEAD, install, relink @opencode/sdk and @opencode/plugin, run the suite (bun install restores the published links). - .github/workflows/ci.yml: install --frozen-lockfile, bun run check, docs drift. nightly.yml: scripts/v2-head.sh packages/opencode on schedule. - scripts/docs.ts + docs:gen/docs:check: emit schemas/*.schema.json (37 Zod contracts, z.toJSONSchema) + docs/SCHEMAS.md; --check fails on drift and stale files. Root zod devDependency added for the generator (same 4.6.5 pin as core, recorded justification: docs tooling under isolated installs). - 203 tests green; docs check green. * M6b: queereye interview core — DTCG tokens, WCAG gate, generated guide - 7-axis schema-typed interview (brand, color, type, layout, effects, dark/light, a11y): one form per axis, recommendations, deterministic counter-questions for vague answers, smuggling refusal for pasted hex/font literals, repair hooks for unknown options and unsafe decoration, and cross-axis contradiction refusal (low-contrast taste vs the a11y gate). - DTCG-shaped token validation: $value/$type/$description only, group $type inheritance, alias chains with circular/dangling errors, mixed raw+alias refusal, list-smuggled keys refused, and one-off mints (raw values outside <domain>.primitive.<name>) as compile errors. - Ratio-first palette generation (WCAG AA 4.5/3, AAA 7 reported): the completed loop emits a primitive -> semantic -> component tree with zero one-offs (reuse ratio ~0.5), and every text pair passes. - Pure renderer: Style-Dictionary-compat CSS vars + STYLE_GUIDE.md, plus .factory/design/ contract (hard error outside, idempotent atomic writes, user-customized files backed up with a conflict note, interview.json resume, corrupt-JSON errors). - Visible 'designer' primary seat, 'design' write scope, /design command, es design status|render|check CLI, queereye skill; designer prompt snapshot. - 24 core tests + 3 real-host tests; 230 total green; generated schemas and docs refreshed. * M6c: four TUI panels + panel RPCs + /research command - Structured panel RPCs on the human-only channel: factoryState (stage, run, spend/ceiling, phases with QA, pending approvals, halt, PR), lspState (servers, availability, running roots, diagnostics), hooksState (handlers, trust, project lines, recent errors, per-handler capability loss), brainstormState (brief, coverage, duplicates, shortlist, outlier). - Four fullscreen panels as session.panel slot claims (panels.tsx): factory dashboard, LSP manager, hook inspector (ADVISORY rows from capabilityLoss) and brainstorm board; commands es-factory / es-lsp-panel / es-hooks / es-brainstorm open them via ui.panel.open. - HookEngine.list() exposes loaded handlers for capability-loss reporting. - /research command: report size, audit coverage from coverage.json and the cached-source count. - Tests: TUI slot/command/open assertions on the fake context, panel RPC shapes on the real host. 232 total green. * M6d: capability matrix, layered config, generated docs, rewrite guides - Capability matrix (packages/core/src/capabilities.ts): 15 capabilities declared per harness; opencode rows are ENFORCED with a proof (test file or the M0 spike record), claude/pi/antigravity rows are declared gaps for 1.1-1.3. enforcedWithoutProof() is a contract the tests and docs enforce. - Canonical config (schema/config.ts + config.ts): models/tiers/agents, afterEdit, spend estimate, PR opener, LSP after-edit, search provider and the darkharvest license whitelist; layered global -> project -> plugin options with recursive per-key merge and strict unknown-key rejection. createRuntime resolves it and the harvest tools default to its whitelist; /config and `es config show` print the effective config and its layers. - Generated docs join the drift pipeline: docs/CAPABILITIES.md (matrix + hook bridge detail; missing proofs fail the generator) and docs/CONFIG.md (from the emitted JSON Schema); docs/SCHEMAS.md refreshed. - README.md and AGENTS.md rewritten for the 1.0 monorepo (the legacy Python guide is gone); testkit isolates XDG_CONFIG_HOME so real-host tests are deterministic against user config files. - 241 tests green (capabilities contract + config layering); docs drift green. * M6e prep: dogfood runbook (factory builds the tree-sitter complexity budget) docs/DOGFOOD.md: how to load the local plugin, grill the feature with a spend ceiling, approve frontier/spec, run the autonomous build, review the draft PR and record the outcome. The run itself needs a human and a real model provider. * CI fix: QA shell sandbox test accepts the allowlist path The runner has no bubblewrap, so the read-only seat refuses 'touch' outright instead of running it in the sandbox. The guarantee under test is that no write escapes; the test now accepts either mechanism (sandbox ran it, or the allowlist refused it) and still asserts the file does not exist. * M6a note: nightly workflow activates at cutover (scheduled workflows only run from the default branch); CI green on rewrite after the sandbox-test fix * M6 remediation 1/6: code scanning, workflow hardening and Sonar security fixes - CodeQL default setup drops the python language (the legacy tree is gone, so the analyzer failed with 'no source code seen during build') - Pin actions/checkout and oven-sh/setup-bun to commit SHAs and set a least-privilege permissions block in ci.yml and nightly.yml; the nightly also gains push-to-rewrite and workflow_dispatch so it can run pre-cutover - bun install --ignore-scripts in CI (v2-head keeps scripts: OpenCode's postinstall fixes node-pty, so that line is NOSONAR-justified) - Fix the missing String.localeCompare comparator in the queereye token walk (Sonar S2871) and drop an unused import - NOSONAR-justify the intentional /tmp permission allow and PATH lookups * M6 remediation 2/6: honest capability rows, self-hosted dependency gate - HOOK_CAPABILITIES: claude/pi/antigravity events are UNSUPPORTED until their adapters ship (1.1-1.3); only opencode is enforced. The generated docs/CAPABILITIES.md no longer claims enforcement for harnesses that do not exist, and capabilities.test now fails any enforced hook row without a proven enforced matrix row. - New core gate src/gates/minimal-deps.ts plus scripts/deps.ts: core's runtime dependencies must stay within the plan's allowlist (zod, web-tree-sitter, vscode-jsonrpc, vscode-languageserver-protocol) or carry a recorded justification in .factory/dependencies.json; wired into 'bun run check'. - Document the deliberate enforcement limits (read-only fallback, control-file baseline scope, advisory MCP caller identity) in README and the MCP instructions string. * M6 remediation 3/6: resolve the CodeQL new-code alerts (45) Fix, not dismiss: - ReDoS (28): replace ambiguous alternations/nested quantifiers with linear single-quantifier patterns and, where regex could not be made safe, hand written scanners (blankBlockComments, stripLiterals, HTML tokenizer). Files: gates/parsers.ts, gates/budgets.ts, structure/extract.ts, research/html.ts, research/auditor.ts, harvest/spdx.ts, harvest/scan.ts, hooks/tools.ts, worktree/git.ts. - HTML sanitization (11): htmlToText now walks a tag tokenizer and never emits raw markup, so no tag-stripping regex remains; scripts/docs.ts escapes backslashes before pipe escaping; replaceAll for the 'first occurrence' spots. - File-system race (3): read through a single descriptor (open + fstat + readFile) in structure/graph.ts and harvest/scan.ts, and re-read the signing key via a helper in approval/keystore.ts. - Prototype pollution (1): reject __proto__/constructor/prototype slot names. - Shell command (1): gates/security.ts resolves binaries by scanning PATH with accessSync instead of interpolating into 'sh -c'. - Missing regexp anchor (1): group the DOC_OR_CONFIG alternatives explicitly. bun run check: 246 tests green; docs:check green. * M6 remediation 4/6: finish CodeQL ReDoS/sanitization and Sonar reliability Second pass after the first fixes still tripped js/polynomial-redos: - budgets.ts: replace the combined function-header regex with an ordered list of linear patterns, taking the leftmost match. - structure/extract.ts: normalize whitespace before the Python import/def patterns; replace the go receiver group with a linear capture; blank line comments with a scanner (lineCommentIndex) instead of a regex. - research/html.ts: locate title/body/main by indexOf instead of tag regexes. - gates/parsers.ts: split the mypy column-optional pattern in two; parse the vitest/pytest/generic trailing text in code instead of in the regex. - research/auditor.ts + queereye/slots.ts: drop the ambiguous whitespace quantifier / inline the __proto__ guard so the analyser recognises it. Sonar reliability (S2871): add explicit code-unit comparators to every argument-less Array#sort in shipped code (order-preserving), and NOSONAR the two probe-fixture /tmp paths under spikes/ (analysis scope decision). bun run check: 246 tests green. * M6 remediation 5/6: clear the last CodeQL ReDoS/PP hits and the CLI PATH vuln - parsers.ts: parse mypy with single-space patterns; parse vitest/jest, pytest and the generic fallback by scanning lines/tokens instead of regexes. - budgets.ts: match function headers against a whitespace-normalised line with single-space patterns. - auditor.ts: tag body uses [^\]]*; structure/extract.ts extracts the Go receiver with a char-code scan (lastWord). - queereye/slots.ts: per-axis value maps use a null prototype. - cli/headless.ts: resolve the opencode binary to an absolute path (accessSync PATH scan) so no child process is spawned via PATH; onPath's 'sh -c' is gone. bun run check: 246 tests green. * M6 remediation 6/6: close the last CodeQL hits (TAG, headers, prototype) - auditor.ts: parseTags walks the line with indexOf/startsWith instead of a regex; the tag body is a plain slice. - budgets.ts: restrict the function-header character classes so no two quantifiers can overlap (params/return types use [\w$ ,:?=*...] classes). - queereye/slots.ts: per-axis answers are a Map (no bracket assignment or delete on a keyed object); store.ts, ops.ts, cli/main.ts and the queereye test follow the Map. Removes the prototype-polluting assignment for good. bun run check: 246 tests green. * M6 remediation: simplify complexity header identifiers (drop $ from classes) * M6 remediation: detect method headers without a signature regex Match 'name(' at line start, then require ')' followed by '{' via indexOf; the regex no longer consumes the parameter/return-type text. * M6 remediation: detect function headers with a scanner, no regex Replace the header regex list (and the last js/polynomial-redos hit) with detectHeader: a linear char scanner for function/fn/func/arrow/method forms. Complexity behaviour is unchanged (the complexity test still passes). * M6 remediation: publishing, cutover note, MinHash + embeddings dedupe - Publish workflow (workflow_dispatch, OIDC trusted publishing + provenance, defaults to dry-run) and per-package prepublishOnly builds so dist exists. - CHANGELOG.md cutover note: no migration, legacy-final tag, breaking change. - Brainstorm dedupe: MinHash (new default) with n-gram still selectable, and an optional OpenAI-compatible embeddings endpoint (config 'embeddings', batching + caching client, async cosine dedupe) wired through the brainstorm tools. - Docs/schemas regenerated; 250 tests green (MinHash + embeddings tests added). * M6 remediation: pin npm and skip lifecycle scripts in the publish workflow * M6 remediation: opt-in, cost-capped behaviour evals - Core grader (packages/core/src/evals/grade.ts) with tests: case-insensitive contains/notContains, collects every failure. - evals/cases/{grill,brainstorm,factory}.json and scripts/evals.ts: runs each case via 'opencode run', bounded by ES_EVAL_TIMEOUT_MS, writes results to evals/results/, and skips cleanly when the CLI is absent. - nightly.yml gains an evals job gated on the ES_EVAL_API_KEY secret; never in the default test run. .gitignore now ignores only evals/results/. * M6 remediation: fix workflow validation (secrets not allowed in if; quote publish flags) * PR #18 remediation 1/8: confine darkharvest to the project; harvested code never executes Review of PR #18 found (probed) that the harvester could plan `local:<state dir>` and read the approval signing key with es_harvest_read, follow symlinks out of a cloned candidate, and trigger a candidate repo's own core.fsmonitor by running `git ls-files` inside it. - assertSourceAllowed: agent-driven local and file-path git sources must canonicalize inside the project; the user-global state dir is refused for everyone; ext:: and other git helper transports are refused. Checked at plan time and again in scanSource. Only the es CLI (a human) passes allowOutside. - Harvested content is untrusted: the structural index walks it instead of running git (GraphOptions.untrusted), license/manifest/candidate reads go through readRegularFile (no symlinks, same-inode check, 2 MB cap), and readCandidate checks containment after resolving symlinks. - The commit comes from .git/HEAD, refs and packed-refs read as files. - shallowClone: GIT_ALLOW_PROTOCOL (file only for allowed local sources), no submodules, no LFS smudge, no terminal prompt, `--` before the URL. - Tests: outside/state-dir/transport refusals, symlink escapes, and an fsmonitor sentinel that must not run. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 2/8: seal engine-owned brainstorm/harvest/design state The seat write scopes covered .factory/<x>/**, and the gated tools read that JSON back: the harvester could hand-edit matrix.json (probe: a GPL candidate ended up in VENDOR-PLAN.md) or a profile's licence, and the brainstormer could write scores.json and skip the critic. - Engine state (plan/ideas/scores/result, harvest plan/matrix/profiles/report/ vendor plan/clean-room specs, design tokens/guide/css) is a factory control file: no agent's host edits may touch it; the tools write through core. The shell control-mention check covers the engine JSON. Seats keep notes/**. - Defense in depth: es_harvest_matrix and es_harvest_complete re-derive every licence from the scanned bytes (currentLicense), and complete re-applies the policy to the stored matrix (recheckMatrix), reporting any downgrade. - Candidate ids never take the reserved notes/ or clean-room/ directories. - Tests: policy matrix for every agent, hand-edited profile and matrix, and a real-host write denial for the harvester. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 3/8: fail-closed SPDX detection by full-text template match The signature detector failed open and misidentified (probed on real texts): the JSON licence ("Good, not Evil") and MIT + Commons Clause came out as MIT, GPL-3.0 as AGPL-3.0 (its section 13 mentions the Affero GPL), LGPL-2.1 as GPL-2.0; one SPDX header in any of 200 files verified a whole repo; only the first licence file counted. - templates.ts: SPDX license-list v3.29.0 templates for the whitelist, bundled in assets/licenses and pinned by sha256 (fetched sources cached under .research/sources). A permissive/public-domain verdict needs the whole file to match: words after SPDX-style normalisation, <<var>> spans checked by their own regex, optional blocks, nothing left over. The leading copyright var absorbs only copyright / rights / short title lines, so a prepended rider cannot hide in it. Memoised matching, no whole-text backtracking regex. - Copyleft and source-available licences by title line first, then by their distinctive date lines; permissive look-alikes are "unknown" with a note. - Every licence file in the root counts (LICENSE*, COPYING*, UNLICENSE); the most restrictive wins; permissive files combine with AND; an unrecognised file makes the project unknown. Headers add restrictions but never verify. - checkVerdict requires every id of an expression to be whitelisted. - Corpus test over real SPDX texts (21 licences) plus riders and edits; over the 1,415 LICENSE files in node_modules every plain whitelisted text matches, and the misses are mixed, notice-only or concatenated files (fail-closed). Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 4/8: the project config is a pinned control file; it cannot pick endpoints, keys or estimates .factory/config.json was agent-writable and unpinned, and its project layer could set embeddings.url plus apiKeyEnv (any env var sent as a Bearer token to any URL) and the estimate rates behind the spend ceiling. The configured licenseWhitelist was never used: the harvest plan took the model's list. - .factory/config.json is a factory control file (editor and shell) and is pinned in the control baseline; a hand edit is drift until a human accepts it. - New `es rebaseline` (TTY + typed code): accept hand edits to pinned control files (gates.json, config.json, frontier) without a full approval. - A project file may not set `embeddings` or `estimate`; global config or plugin options only (clear error naming both files). - es_harvest_plan may only narrow the configured whitelist; ids outside it are reported as ignored. - Docs regenerated (schema descriptions). Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 5/8: undo the ReDoS-rewrite regressions in the gates The CodeQL-driven rewrites traded correctness for regex shape: - complexity: detectHeader dropped TS methods and arrows with return types (probe: `method(x: number): string {` was never measured, so the budget silently skipped it) and cut parameter lists at the first ")". It now matches parentheses by depth and accepts an optional `: ReturnType` before `{`/`=>`. - tsc parser: `[^()]` lost every finding for paths with parentheses (Next.js route groups). Lines are now split at the diagnostic marker, plain and pretty. - parseTags: brackets inside a tag body (a quote citing "[1]") ended the tag; the scan now matches depth. - affected tests: the graph selected helpers under test/ as tests; only runnable test files are selected (helpers are still traversed), and bun gets "./" paths so arguments are paths, not name filters. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 6/8: publish what users install (pack, smoke, then publish the tarballs) - `npm publish` from the package folders would have shipped "@heretek-ai/es-core": "workspace:*" literally. Publishing now packs with `bun pm pack` (which rewrites workspace:* to real versions) and publishes exactly those tarballs with provenance. - The CLI bundle inlined core, so core's assets resolved outside the installed package (probe: `es harvest scan` under Node failed with ENOENT on the licence templates). The CLI now keeps its dependencies external and uses core's own dist. - scripts/pack-smoke.sh builds, packs, npm-installs the three tarballs, refuses a leaked workspace: protocol, runs `es --help` and a real harvest scan under Node, loads core's prompts and skills, and imports the plugin's server entry under Bun. CI runs it on Node 22 (the minimum engine); publish runs it first and publishes its tarballs. setup-node is pinned to the v7.0.0 commit SHA. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 7/8: panels render for real and follow the run; capability rows cite our own proofs - Panels fetched once and never refreshed, and their only test was a fake slot that never rendered JSX. They now refetch on the server's `changed` event and every 2 s while open (usePanelState), and RPC failures render as text. - test/panels.test.ts renders all four panels with OpenTUI's headless test renderer and the reactive Solid build (subprocess with the Solid preload, so the transform stays out of the real-host tests) and asserts the frames, including a refresh after a change event and a failure state. - New real-host tests for rows that cited only the M0 spike: per-seat skill scoping, primaries keep the question tool while subagent seats lose it, the factory invokes a hidden seat it may spawn, and compaction carries the factory state. The capability matrix now cites these tests; docs regenerated. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation 8/8: real, capped evals; headless runs in the right project; prior art with provenance - Found while building the eval runner: `opencode run` resolves its project from PWD, not the spawn cwd. The headless driver inherited the caller's PWD, so `es --cwd <project> factory run --headless` drove OpenCode in the wrong project. It now sets PWD to the project root (test: a stub CLI that reports the PWD it was given; red before the fix). - Evals were hollow (no cost cap, no plugin or provider wiring, checks that only looked for crash strings; the CI job always skipped). Now each case is one real `opencode run` turn in an isolated workspace (project, HOME, XDG) that loads this plugin with ES_EVAL_MODEL, graded from the JSON event stream (text, tools used / not used, error events) and killed at a per-case step cap or timeout — the stream has no cost events, so steps bound the spend. Cases check behaviour: the grill asks before writing the frontier, the brainstormer plans with es_brainstorm_plan, the factory with no run points at the grill and starts nothing. Tested on the real CLI with the fake model (skipped without the CLI). The nightly job installs the CLI's platform package (no install scripts) and runs only when the model and key are set. - Brainstorm prior art was model-asserted. es_harvest_prior_art records its searches under .factory/runtime (agents cannot write it), and es_brainstorm_complete accepts only URLs a recorded search returned. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation: docs follow the fixes (limits, dogfood config, changelog) - README "Known enforcement limits": config.json is pinned (es rebaseline), engine state is deny-write, licence detection is strict by design (mixed, notice-only and concatenated licence files are clean-room), agents harvest only inside the project, evals are opt-in and step-capped; pack-smoke in the development commands. - DOGFOOD: commit the project config before approving the frontier (or es rebaseline later); embeddings/estimate belong in the global config. - CHANGELOG: fail-closed licence verdicts and the tarball publishing path. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation: clear the SonarCloud quality gate without changing behaviour The PR's quality gate failed after the remediation push (reliability D, security B), mostly on older code under newer rules (S8786 super-linear regexes, S7781, S7758, S7503, shell [[ ]]) plus a few in the new code. - Each flagged regex is now a scanner or an anchored, linear test: mypy, jest and go-test parsing, TOML licence fields, the tar NUL strip, the import fallback, markdown links and ellipses in quotes, the hook verdict JSON, patch targets, go.mod and requirements pins, the run id, YAML keys and comments, kebab-case doc names. Every rewrite was diffed against the previous implementation (178 repo files for the import scanner, prompts and skills plus edge cases for YAML, quote/patch/go.mod/requirements/run-id samples): identical output. New parser tests pin mypy, jest and go test. - Sort comparators, replaceAll, codePointAt, no async without await (the factory's mutate and the gates' timed now accept sync callbacks), crypto.timingSafeEqual for MAC comparison, git spawned by absolute path in the eval workspace (findExecutable), [[ ]] in v2-head.sh. - The M0 spike suite (17/17) still passes with its probe plugin's promise executors rewritten without async. Co-Authored-By: Claude Opus 5.5 <[email protected]> * PR #18 remediation: resolve the two CodeQL alerts in the new code - js/file-system-race (util/fs.ts readRegularFile): the lstat-then-open check is replaced by opening with O_NOFOLLOW, so a symlink fails to open and there is no check-then-use window at all. - js/bad-tag-filter (spdx.ts header parsing): instead of deleting comment closers (`-->`, `*/`, `#`) from the header line, keep the expression itself (ids, AND/OR/WITH, parentheses) and drop tokens without letters or digits; the header test now includes an HTML-comment header. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: John Smith <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
45 lines
826 B
JSON
45 lines
826 B
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"type": "object",
|
|
"properties": {
|
|
"values": {
|
|
"type": "object",
|
|
"propertyNames": {
|
|
"type": "string"
|
|
},
|
|
"additionalProperties": {
|
|
"type": "object",
|
|
"propertyNames": {
|
|
"type": "string"
|
|
},
|
|
"additionalProperties": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"skipped": {
|
|
"type": "object",
|
|
"propertyNames": {
|
|
"type": "string"
|
|
},
|
|
"additionalProperties": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"token_errors": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"values",
|
|
"skipped"
|
|
],
|
|
"additionalProperties": false
|
|
}
|