diff --git a/.modonome/snapshot/badge.json b/.modonome/snapshot/badge.json
index 4b892bb5..cbc71fc5 100644
--- a/.modonome/snapshot/badge.json
+++ b/.modonome/snapshot/badge.json
@@ -1 +1 @@
-{"color":"blue","label":"snapshot","message":"970 files, 131059 tok","schemaVersion":1}
+{"color":"blue","label":"snapshot","message":"972 files, 131084 tok","schemaVersion":1}
diff --git a/.modonome/snapshot/map.json b/.modonome/snapshot/map.json
index 33bac235..bfebc6ba 100644
--- a/.modonome/snapshot/map.json
+++ b/.modonome/snapshot/map.json
@@ -1 +1 @@
-{"api":[{"anchor":"S:c5854b8940","doc":"Recursively snapshot path -> \"size:sha-like(content)\" for every file.","kind":"function","line":27,"name":"snapshot","path_id":"F:0103cf3d56","signature":"async function snapshot(dir)"},{"anchor":"S:44e7188c1d","doc":"Tiny content hash (FNV-1a): avoids a crypto import and is deterministic.","kind":"function","line":50,"name":"hash","path_id":"F:0103cf3d56","signature":"function hash(buf)"},{"anchor":"S:4ee042ed06","kind":"function","line":59,"name":"makeHostRepo","path_id":"F:0103cf3d56","signature":"async function makeHostRepo()"},{"anchor":"S:08df8d7472","kind":"function","line":70,"name":"runPreflight","path_id":"F:0103cf3d56","signature":"function runPreflight(target)"},{"anchor":"S:c47beeac78","doc":"Normalize a relative import against the importing file's directory, resolving \".\" and \"..\" segments. Returns a posix path with no leading \"./\".","kind":"function","line":11,"name":"normalizeRelative","path_id":"F:015261eab0","signature":"function normalizeRelative(fromPath, module)"},{"anchor":"S:0d7b0da50a","doc":"Resolve a relative import to a repo file, trying common extensions and index files. External and bare imports return null and become no edge.","kind":"function","line":24,"name":"resolveImport","path_id":"F:015261eab0","signature":"function resolveImport(fromPath, module, fileSet)"},{"anchor":"S:c732826ee5","doc":"Build an adjacency map { relPath -> [relPath, ...] } from per-file imports. Only edges that resolve to another repo file are kept.","kind":"function","line":41,"name":"buildImportGraph","path_id":"F:015261eab0","signature":"export function buildImportGraph(perFile, fileSet)"},{"anchor":"S:79144070a6","doc":"Degree centrality: out-edges of a node plus in-edges pointing at it.","kind":"function","line":55,"name":"centrality","path_id":"F:015261eab0","signature":"export function centrality(adj)"},{"anchor":"S:bb578790a3","doc":"PageRank over the import graph. Fixed iteration count keeps it deterministic. Dangling nodes (no out-edges) redistribute their rank uniformly.","kind":"function","line":67,"name":"pagerank","path_id":"F:015261eab0","signature":"export function pagerank(adj, { damping = 0.85, iterations = 40 } = {})"},{"anchor":"S:4d0bae812e","kind":"function","line":91,"name":"round","path_id":"F:015261eab0","signature":"function round(n, places = 6)"},{"anchor":"S:b88ce47ede","doc":"Rank files by a normalized composite of churn, centrality, and PageRank. Returns a sorted list of { path, churn, centrality, pagerank, score }, highest first.","kind":"function","line":98,"name":"attentionRank","path_id":"F:015261eab0","signature":"export function attentionRank(paths, { churn = new Map(), centralityMap = new Map(), pagerankMap = new Map() } = {})"},{"anchor":"S:5ad0c942a1","doc":"Report whether the import graph has a cycle and one example cycle, reusing the shared cycle detector so the snapshot can warn about circular dependencies.","kind":"function","line":117,"name":"findCycle","path_id":"F:015261eab0","signature":"export function findCycle(adj)"},{"anchor":"S:1e6749f65a","kind":"function","line":31,"name":"run","path_id":"F:02a5f8fc55","signature":"function run(env)"},{"anchor":"S:c932c7339f","doc":"Build a minimal repo that satisfies the root allow-list, protected-file manifest, link integrity, and audit-naming checks, so only the ADR-number logic under test can make the run fail or pass.","kind":"function","line":15,"name":"makeMinimalRepo","path_id":"F:0391f3b249","signature":"function makeMinimalRepo()"},{"anchor":"S:0ab594146c","kind":"function","line":33,"name":"runScript","path_id":"F:0391f3b249","signature":"function runScript(tmp)"},{"anchor":"S:689125598d","doc":"A git-init'd variant of makeMinimalRepo(), for the staleness check, which shells out to `git log` and needs a real repository to query.","kind":"function","line":43,"name":"makeMinimalGitRepo","path_id":"F:0391f3b249","signature":"function makeMinimalGitRepo()"},{"anchor":"S:bac2ebbef5","kind":"function","line":53,"name":"gitCommit","path_id":"F:0391f3b249","signature":"function gitCommit(tmp, message)"},{"anchor":"S:cd2e7eba8f","doc":"Commit with an explicit, backdated timestamp, so staleness tests do not depend on same-day wall-clock ordering between setup commits and a `last_reviewed` stamp (git's `--since` treats a bare date as ","kind":"function","line":61,"name":"gitCommitAt","path_id":"F:0391f3b249","signature":"function gitCommitAt(tmp, message, isoDate)"},{"anchor":"S:405ee38bbe","kind":"const","line":65,"name":"CATALOG_PARTIALS","path_id":"F:03f476958e","signature":"export const CATALOG_PARTIALS = ["},{"anchor":"S:949f988c9e","kind":"function","line":10,"name":"makeDb","path_id":"F:044b762a79","signature":"function makeDb(orders = new Map())"},{"anchor":"S:e96fb86528","doc":"Catalog entries for scripts/check-edit-set-compliance.mjs.","kind":"const","line":2,"name":"MESSAGES","path_id":"F:05a0f0d5a5","signature":"export const MESSAGES ="},{"anchor":"S:f8524caefc","kind":"const","line":18,"name":"SEVERITY_RANK","path_id":"F:05bffc70e9","signature":"export const SEVERITY_RANK = { ok: 0, info: 1, attention: 2, blocked: 3 };"},{"anchor":"S:c12913d4da","kind":"function","line":22,"name":"mergeCatalog","path_id":"F:05bffc70e9","signature":"function mergeCatalog(sources)"},{"anchor":"S:4bea381dfd","kind":"const","line":33,"name":"MESSAGES","path_id":"F:05bffc70e9","signature":"export const MESSAGES = mergeCatalog(CATALOG_SOURCES);"},{"anchor":"S:81c9c1291a","kind":"function","line":35,"name":"interpolate","path_id":"F:05bffc70e9","signature":"function interpolate(template, params)"},{"anchor":"S:db0bb71f37","doc":"Clamp a requested severity to an entry's floor. Only ever raises severity toward (never past) the catalog default for non_suppressible entries.","kind":"function","line":41,"name":"clampSeverity","path_id":"F:05bffc70e9","signature":"function clampSeverity(entry, requestedSeverity)"},{"anchor":"S:a79dad6e97","kind":"function","line":48,"name":"loadMessageOverrides","path_id":"F:05bffc70e9","signature":"export function loadMessageOverrides(modonomeDir)"},{"anchor":"S:0044d1a126","doc":"Validate an overrides document (the parsed contents of messages.yaml) against both the JSON schema and the severity-floor rule. Shared by scripts/check-message-catalog-integrity.mjs (CI) and the contr","kind":"function","line":59,"name":"checkOverridesIntegrity","path_id":"F:05bffc70e9","signature":"export function checkOverridesIntegrity(overridesDoc, schema)"},{"anchor":"S:8282a0b575","doc":"Look up a message by id, apply any operator override (clamped to the floor for non_suppressible entries), interpolate {param} tokens, and return the resolved { id, severity, suppressed, message } read","kind":"function","line":85,"name":"formatMessage","path_id":"F:05bffc70e9","signature":"export function formatMessage(id, params = {}, overrides = {})"},{"anchor":"S:6dde857e83","doc":"List every catalog entry with its resolved (override-applied) state, for the control panel's Messages tab.","kind":"function","line":104,"name":"listMessages","path_id":"F:05bffc70e9","signature":"export function listMessages(overrides = {})"},{"anchor":"S:ab3548c3d0","kind":"function","line":16,"name":"baseCfg","path_id":"F:06b982f5a2","signature":"function baseCfg(extra = {})"},{"anchor":"S:0a11409d06","doc":"Full detail for a single work item, as shown in the read-only inspector drawer. * Extends the card summary shape with the fields only needed once someone opens the * item: identities, lease, allowed e","kind":"interface","line":14,"name":"WorkItemDetail","path_id":"F:08064e0c53","signature":"export interface WorkItemDetail extends WorkItemSummary"},{"anchor":"S:6a4d8aa30d","kind":"interface","line":31,"name":"WorkItemDrawerProps","path_id":"F:08064e0c53","signature":"export interface WorkItemDrawerProps"},{"anchor":"S:1e67af68fc","kind":"function","line":52,"name":"Section","path_id":"F:08064e0c53","signature":"function Section({ label, children }: { label: string; children: ReactNode })"},{"anchor":"S:fff471613b","doc":"A read-only inspector for a single work item, presented in the shared `Drawer` * primitive. Lays out status, the maker and checker identities, lease and branch * info, attempt count, the allowed edit ","kind":"function","line":68,"name":"WorkItemDrawer","path_id":"F:08064e0c53","signature":"export function WorkItemDrawer({ item, open, onClose }: WorkItemDrawerProps)"},{"anchor":"S:9f9c07db7d","kind":"function","line":10,"name":"Model","path_id":"F:08577063d4","signature":"export const Model = () => ("},{"anchor":"S:d3f17c584a","kind":"function","line":26,"name":"isSelfGovernance","path_id":"F:08b7435c86","signature":"function isSelfGovernance(dir)"},{"anchor":"S:02e2e85572","kind":"function","line":30,"name":"resolveModonomeDir","path_id":"F:08b7435c86","signature":"function resolveModonomeDir(rawMode, dirParam)"},{"anchor":"S:8097fe47fc","kind":"function","line":40,"name":"readBody","path_id":"F:08b7435c86","signature":"function readBody(req)"},{"anchor":"S:a10a756308","kind":"function","line":59,"name":"sendJson","path_id":"F:08b7435c86","signature":"function sendJson(res, status, body)"},{"anchor":"S:0e6240f5b7","doc":"The single source of truth for \"may a write to this dir proceed\", used both to decide a 403 and to set source.writable, so the two can never drift. Returns the base flag first (off => nothing is writa","kind":"function","line":70,"name":"writeGate","path_id":"F:08b7435c86","signature":"function writeGate(baseWritable, dir)"},{"anchor":"S:b06f3444be","kind":"function","line":86,"name":"stateWithSource","path_id":"F:08b7435c86","signature":"function stateWithSource(baseWritable, dir, mode)"},{"anchor":"S:62210684b4","doc":"Best-effort reachability probe for an OpenAI-compatible endpoint (LM Studio, Ollama, a gateway). Read-only and network-only: it never touches config.yaml, so it needs no write guard. Always resolves (","kind":"function","line":98,"name":"buildModelsUrl","path_id":"F:08b7435c86","signature":"function buildModelsUrl(baseUrl)"},{"anchor":"S:3f9e6b3a7b","kind":"function","line":104,"name":"testConnection","path_id":"F:08b7435c86","signature":"async function testConnection(baseUrl)"},{"anchor":"S:5092562c12","kind":"function","line":130,"name":"modonomeApiPlugin","path_id":"F:08b7435c86","signature":"export function modonomeApiPlugin()"},{"anchor":"S:9b40c124ce","kind":"function","line":17,"name":"baseCfg","path_id":"F:093689bb8e","signature":"function baseCfg(extra = {})"},{"anchor":"S:7078ce1661","kind":"function","line":40,"name":"today","path_id":"F:09ba331878","signature":"function today()"},{"anchor":"S:735c642c3a","doc":"Gather every near-miss across the branch name, commit identities, and commit bodies unique to this branch.","kind":"function","line":46,"name":"collectNearMisses","path_id":"F:09ba331878","signature":"export function collectNearMisses({ branch, commits })"},{"anchor":"S:4358d9c393","doc":"A denylist proposal is per unique (tier, surface, token): the widener proposes adding a token, not fixing N occurrences. Keep the first occurrence as evidence.","kind":"function","line":67,"name":"proposalsFrom","path_id":"F:09ba331878","signature":"export function proposalsFrom(findings)"},{"anchor":"S:b89188d9e3","kind":"function","line":76,"name":"main","path_id":"F:09ba331878","signature":"function main(argv)"},{"anchor":"S:79997ba94d","kind":"const","line":1,"name":"MESSAGES","path_id":"F:09ea014068","signature":"export const MESSAGES ="},{"anchor":"S:b29fc4b0d5","kind":"function","line":3,"name":"ArmEngine","path_id":"F:0a6a758e7d","signature":"export const ArmEngine = () => ("},{"anchor":"S:8cd25e6f09","kind":"type","line":10,"name":"PanelMode","path_id":"F:0a85f3b8e5","signature":"export type PanelMode = \"host\" | \"product\";"},{"anchor":"S:40a4170626","kind":"type","line":11,"name":"ArmingMode","path_id":"F:0a85f3b8e5","signature":"export type ArmingMode = \"disabled\" | \"dry-run\" | \"armed\";"},{"anchor":"S:49f97badd7","kind":"type","line":12,"name":"WorkState","path_id":"F:0a85f3b8e5","signature":"export type WorkState ="},{"anchor":"S:3e9158c80b","kind":"type","line":22,"name":"RiskTier","path_id":"F:0a85f3b8e5","signature":"export type RiskTier = 1 | 2 | 3 | 4;"},{"anchor":"S:86cb290127","doc":"The subject a mode points at: which repo the panel is reading.","kind":"interface","line":25,"name":"Subject","path_id":"F:0a85f3b8e5","signature":"export interface Subject"},{"anchor":"S:a337ae8f0b","doc":"The engine configuration (schemas/config.schema.json), the levers the panel edits.","kind":"interface","line":37,"name":"ModonomeConfig","path_id":"F:0a85f3b8e5","signature":"export interface ModonomeConfig"},{"anchor":"S:577a1daeb3","kind":"type","line":85,"name":"MessageSeverity","path_id":"F:0a85f3b8e5","signature":"export type MessageSeverity = \"ok\" | \"info\" | \"attention\" | \"blocked\";"},{"anchor":"S:6605365375","doc":"One entry of the built-in message catalog (scripts/lib/messages.mjs), with * this subject's .modonome/messages.yaml overrides already resolved. A * non_suppressible entry's severity/suppressed always ","kind":"interface","line":94,"name":"MessageCatalogEntryVM","path_id":"F:0a85f3b8e5","signature":"export interface MessageCatalogEntryVM"},{"anchor":"S:d22e005d52","doc":"A patch to one message's override, as sent to onSaveMessages. Omitted * fields reset to the catalog default; severity/suppressed are rejected * server-side for a non_suppressible id.","kind":"interface","line":108,"name":"MessageOverridePatch","path_id":"F:0a85f3b8e5","signature":"export interface MessageOverridePatch"},{"anchor":"S:d56c1854d7","doc":"One prerequisite in the armed-mode gate checklist.","kind":"interface","line":115,"name":"ArmingCheck","path_id":"F:0a85f3b8e5","signature":"export interface ArmingCheck"},{"anchor":"S:6bc87187a8","kind":"interface","line":123,"name":"ArmingStatus","path_id":"F:0a85f3b8e5","signature":"export interface ArmingStatus"},{"anchor":"S:a4a9a79fbe","kind":"type","line":130,"name":"WorkItemType","path_id":"F:0a85f3b8e5","signature":"export type WorkItemType = \"fix-issue\" | \"develop-feature\" | \"create-article\" | \"create-plan\" | \"update-docs\" | \"chore\";"},{"anchor":"S:3f93aaa307","doc":"True for any state where a real actor could be actively working the item: * mutating it destructively (delete) needs the lease released first.","kind":"const","line":134,"name":"IN_FLIGHT_STATES","path_id":"F:0a85f3b8e5","signature":"export const IN_FLIGHT_STATES: WorkState[] = [\"claimed\", \"making\", \"checking\", \"rework\", \"merge_ready\", \"merging\"];"},{"anchor":"S:5a49db2766","kind":"interface","line":136,"name":"WorkItemVM","path_id":"F:0a85f3b8e5","signature":"export interface WorkItemVM"},{"anchor":"S:f3e5c99141","kind":"interface","line":162,"name":"LeaseVM","path_id":"F:0a85f3b8e5","signature":"export interface LeaseVM"},{"anchor":"S:dddb39652d","kind":"type","line":169,"name":"GateStatus","path_id":"F:0a85f3b8e5","signature":"export type GateStatus = \"pass\" | \"fail\" | \"flaky\" | \"running\" | \"pending\";"},{"anchor":"S:9bc07de53c","kind":"interface","line":171,"name":"GateVM","path_id":"F:0a85f3b8e5","signature":"export interface GateVM"},{"anchor":"S:126357e421","kind":"interface","line":180,"name":"CostByModel","path_id":"F:0a85f3b8e5","signature":"export interface CostByModel"},{"anchor":"S:ebe2964819","kind":"interface","line":188,"name":"CostVM","path_id":"F:0a85f3b8e5","signature":"export interface CostVM"},{"anchor":"S:72a5c214ac","kind":"interface","line":197,"name":"LearningVM","path_id":"F:0a85f3b8e5","signature":"export interface LearningVM"},{"anchor":"S:e03cf612ca","kind":"interface","line":207,"name":"DecisionVM","path_id":"F:0a85f3b8e5","signature":"export interface DecisionVM"},{"anchor":"S:6ef3b2f2e5","doc":"One commit the metadata-only remediator would rewrite, and why.","kind":"interface","line":217,"name":"RemediationProposalVM","path_id":"F:0a85f3b8e5","signature":"export interface RemediationProposalVM"},{"anchor":"S:b41535d6e7","doc":"The armed metadata-only remediator (ADR-035) as a read-only surface plus one owner * lever. `applyEnabled` mirrors the config flag; `ready` is true only when every arming * condition is met, and `bloc","kind":"interface","line":228,"name":"RemediationVM","path_id":"F:0a85f3b8e5","signature":"export interface RemediationVM"},{"anchor":"S:3ad2d564a8","kind":"type","line":237,"name":"AuditKind","path_id":"F:0a85f3b8e5","signature":"export type AuditKind ="},{"anchor":"S:7c6ba2a644","kind":"interface","line":252,"name":"AuditEventVM","path_id":"F:0a85f3b8e5","signature":"export interface AuditEventVM"},{"anchor":"S:19226d4902","kind":"interface","line":259,"name":"ProtectedPathVM","path_id":"F:0a85f3b8e5","signature":"export interface ProtectedPathVM"},{"anchor":"S:61e677ae40","kind":"interface","line":266,"name":"TrendPoint","path_id":"F:0a85f3b8e5","signature":"export interface TrendPoint"},{"anchor":"S:cefb8c3f64","doc":"Where a loaded PanelState actually came from, so the UI never presents demo data as real.","kind":"interface","line":272,"name":"PanelSource","path_id":"F:0a85f3b8e5","signature":"export interface PanelSource"},{"anchor":"S:4a0171ecb5","kind":"interface","line":285,"name":"PanelState","path_id":"F:0a85f3b8e5","signature":"export interface PanelState"},{"anchor":"S:6dcad3cdf1","doc":"Fields a new work item is created with. Always starts in state \"queued\".","kind":"interface","line":321,"name":"NewWorkItemInput","path_id":"F:0a85f3b8e5","signature":"export interface NewWorkItemInput"},{"anchor":"S:7934857ce3","doc":"Safe-to-edit-anytime fields: never state, owner, or lease, since those change only * through the existing lease/transition machinery, never a generic metadata edit.","kind":"interface","line":333,"name":"WorkItemPatch","path_id":"F:0a85f3b8e5","signature":"export interface WorkItemPatch"},{"anchor":"S:a2d9480f78","kind":"interface","line":342,"name":"WriteActions","path_id":"F:0a85f3b8e5","signature":"export interface WriteActions"},{"anchor":"S:6dd199eea1","doc":"Resolve an alias to an active, in-window key entry in the allowlist. `overrides` (from loadMessageOverrides()) is an optional caller-supplied parameter rather than something this function reads itself","kind":"function","line":24,"name":"resolveActiveKey","path_id":"F:0c1c5ad5d9","signature":"export function resolveActiveKey(peerKeys, alias, now = new Date(), overrides = {})"},{"anchor":"S:f3b8628cdb","doc":"Full ordered verification. options.skipContentGate runs only the signature checks (steps 3 to 5), used when the caller already ran the schema and redaction gate.","kind":"function","line":41,"name":"verifyPacket","path_id":"F:0c1c5ad5d9","signature":"export function verifyPacket(packet, peerKeys, { now = new Date(), skipContentGate = false, overrides = {} } = {})"},{"anchor":"S:0af608ade0","kind":"const","line":1,"name":"MESSAGES","path_id":"F:0c731e3460","signature":"export const MESSAGES ="},{"anchor":"S:ee5246d16c","kind":"function","line":14,"name":"generateKeypair","path_id":"F:0cacf66a3b","signature":"export function generateKeypair()"},{"anchor":"S:842e875c5a","doc":"Raw 32-byte public key as base64, accepting either a public or private KeyObject.","kind":"function","line":19,"name":"publicKeyB64","path_id":"F:0cacf66a3b","signature":"export function publicKeyB64(keyObject)"},{"anchor":"S:8a971e3c54","doc":"Public KeyObject from a raw 32-byte base64 public key.","kind":"function","line":26,"name":"publicKeyFromB64","path_id":"F:0cacf66a3b","signature":"export function publicKeyFromB64(b64)"},{"anchor":"S:380b82547c","doc":"Private KeyObject from base64 PKCS8 DER (the env-secret format).","kind":"function","line":32,"name":"privateKeyFromB64Pkcs8","path_id":"F:0cacf66a3b","signature":"export function privateKeyFromB64Pkcs8(b64)"},{"anchor":"S:19e5ddb185","kind":"function","line":36,"name":"privateKeyToB64Pkcs8","path_id":"F:0cacf66a3b","signature":"export function privateKeyToB64Pkcs8(keyObject)"},{"anchor":"S:1c7919b4ea","kind":"function","line":40,"name":"signMessage","path_id":"F:0cacf66a3b","signature":"export function signMessage(message, privateKeyObject)"},{"anchor":"S:fb81ef11a3","kind":"function","line":44,"name":"verifyMessage","path_id":"F:0cacf66a3b","signature":"export function verifyMessage(message, sigB64, publicKeyObject)"},{"anchor":"S:4a08c48993","doc":"Short fingerprint for out-of-band key comparison (ADR-017 enrollment): the first 16 hex characters of sha256 over the raw public key bytes.","kind":"function","line":54,"name":"fingerprint","path_id":"F:0cacf66a3b","signature":"export function fingerprint(pubB64)"},{"anchor":"S:f2e1ea8458","kind":"function","line":16,"name":"deriveMode","path_id":"F:0da05a2a05","signature":"export function deriveMode(config: ModonomeConfig, envArmed: boolean): ArmingMode"},{"anchor":"S:97bc3f0eb4","kind":"function","line":22,"name":"deriveArming","path_id":"F:0da05a2a05","signature":"export function deriveArming("},{"anchor":"S:a3fb13b441","kind":"function","line":4,"name":"Tones","path_id":"F:10e76cfcd3","signature":"export const Tones = () => ("},{"anchor":"S:14ef0a45e8","kind":"const","line":1,"name":"MESSAGES","path_id":"F:1127892e72","signature":"export const MESSAGES ="},{"anchor":"S:a1d4334d94","kind":"function","line":44,"name":"App","path_id":"F:113387361d","signature":"export function App()"},{"anchor":"S:670e55d75a","kind":"const","line":10,"name":"CACHE_SCHEMA_VERSION","path_id":"F:119e3c0fce","signature":"export const CACHE_SCHEMA_VERSION = 1;"},{"anchor":"S:31032f0509","doc":"A value safe to pass as a git revision argument: a short-to-full hex SHA. Rejects anything else, in particular a leading \"-\", which git would parse as an option (some git options can read or write fil","kind":"function","line":17,"name":"isPlausibleRevision","path_id":"F:119e3c0fce","signature":"export function isPlausibleRevision(value)"},{"anchor":"S:7762c6d861","kind":"function","line":21,"name":"cachePath","path_id":"F:119e3c0fce","signature":"function cachePath(root)"},{"anchor":"S:59b9039619","doc":"Load the cache for a repo, or null when absent, unreadable, or a different version.","kind":"function","line":28,"name":"loadCache","path_id":"F:119e3c0fce","signature":"export function loadCache(root)"},{"anchor":"S:ba5f7d1ffe","doc":"Persist the cache. entries is { relPath: { hash, symbols, imports, purposeRaw } }.","kind":"function","line":41,"name":"saveCache","path_id":"F:119e3c0fce","signature":"export function saveCache(root, { built_at_head = null, entries = {} })"},{"anchor":"S:ed24428ce0","doc":"The current git HEAD sha for the repo, or null when unavailable.","kind":"function","line":50,"name":"gitHead","path_id":"F:119e3c0fce","signature":"export function gitHead(root)"},{"anchor":"S:236237bc1b","doc":"Strip git's optional quoting from a porcelain path.","kind":"function","line":56,"name":"unquote","path_id":"F:119e3c0fce","signature":"function unquote(p)"},{"anchor":"S:93d0a78f18","doc":"The set of paths that changed since the cache was built: uncommitted work (git status) plus commits since cache.built_at_head. Returns null when git is not usable, which forces a full rebuild.","kind":"function","line":65,"name":"changedPaths","path_id":"F:119e3c0fce","signature":"export function changedPaths(root, cache)"},{"anchor":"S:c3d94f0812","doc":"Pull \"owner/repo\" out of a repository URL such as https://github.com/enumind/modonome(.git). Returns \"\" when it does not parse.","kind":"function","line":32,"name":"parseRepoFromUrl","path_id":"F:128b647d9a","signature":"export function parseRepoFromUrl(url)"},{"anchor":"S:d1b03afffb","doc":"Derive a stable repo label. The generator block credits the tool (generator.name is always \"modonome\"), so the per-repo identity lives in generator.repository. Prefer that, then fall back to the filen","kind":"function","line":41,"name":"deriveRepoName","path_id":"F:128b647d9a","signature":"export function deriveRepoName(att, filename)"},{"anchor":"S:3a57c07db5","doc":"Three-way posture from the attestation posture block.","kind":"function","line":48,"name":"derivePosture","path_id":"F:128b647d9a","signature":"export function derivePosture(posture)"},{"anchor":"S:26df582c22","doc":"Build one row from a filename and its raw text. A parse or shape problem is recorded on the row and reported as a table cell; it never throws, so one bad file cannot crash the whole run.","kind":"function","line":57,"name":"buildRow","path_id":"F:128b647d9a","signature":"export function buildRow(filename, text)"},{"anchor":"S:ba36fd17d6","doc":"Read every *.json file in dir and build a row for each. Files are read once with readFileSync (no separate stat then read, so there is no check-to-use race window). Returns unsorted rows.","kind":"function","line":100,"name":"collectRows","path_id":"F:128b647d9a","signature":"export function collectRows(dir)"},{"anchor":"S:c42dd60d39","doc":"Deterministic order: by repo label, then by filename as a tie-break.","kind":"function","line":126,"name":"sortRows","path_id":"F:128b647d9a","signature":"export function sortRows(rows)"},{"anchor":"S:7619cf060d","kind":"function","line":133,"name":"escapeHtml","path_id":"F:128b647d9a","signature":"function escapeHtml(s)"},{"anchor":"S:7bcf8115de","kind":"function","line":141,"name":"capabilitiesCell","path_id":"F:128b647d9a","signature":"function capabilitiesCell(caps)"},{"anchor":"S:b366c411d2","doc":"Render the sorted rows to a self-contained HTML document. Pure: given the same rows and options it returns the same string.","kind":"function","line":150,"name":"renderHtml","path_id":"F:128b647d9a","signature":"export function renderHtml(rows, options = {})"},{"anchor":"S:5afb2ca954","doc":"Full pipeline: directory to HTML string. Exported for tests.","kind":"function","line":225,"name":"renderLedgerFromDir","path_id":"F:128b647d9a","signature":"export function renderLedgerFromDir(dir, options = {})"},{"anchor":"S:0255163ba3","kind":"function","line":229,"name":"parseArgs","path_id":"F:128b647d9a","signature":"function parseArgs(argv)"},{"anchor":"S:cecb0a4a33","kind":"function","line":248,"name":"main","path_id":"F:128b647d9a","signature":"function main(argv)"},{"anchor":"S:3968554637","kind":"const","line":8,"name":"VOLATILE_FIELDS","path_id":"F:12c7a4e461","signature":"export const VOLATILE_FIELDS = ['id', 'signature'];"},{"anchor":"S:9f7fa8d585","kind":"function","line":10,"name":"packetContent","path_id":"F:12c7a4e461","signature":"export function packetContent(packet)"},{"anchor":"S:a0ea4d9d0f","kind":"function","line":18,"name":"computePacketId","path_id":"F:12c7a4e461","signature":"export function computePacketId(packet)"},{"anchor":"S:d2ef86c19f","kind":"function","line":23,"name":"packetIdMatches","path_id":"F:12c7a4e461","signature":"export function packetIdMatches(packet)"},{"anchor":"S:4700befa2a","kind":"function","line":16,"name":"run","path_id":"F:137056535b","signature":"function run(args = [], env = {})"},{"anchor":"S:bc56c13940","doc":"Restore the committed (current, unsigned) artifact after any test that writes to it, so the suite leaves no drift behind.","kind":"function","line":22,"name":"preservingArtifact","path_id":"F:137056535b","signature":"function preservingArtifact(fn)"},{"anchor":"S:2cd4d9571d","kind":"function","line":189,"name":"withTempFile","path_id":"F:137056535b","signature":"function withTempFile(name, content, fn)"},{"anchor":"S:5708b6bd2b","kind":"function","line":4,"name":"PendingApproval","path_id":"F:13d31b33ea","signature":"export const PendingApproval = () => ("},{"anchor":"S:4f265e8008","kind":"function","line":8,"name":"Approved","path_id":"F:13d31b33ea","signature":"export const Approved = () => ("},{"anchor":"S:93e0292f30","kind":"function","line":12,"name":"Protected","path_id":"F:13d31b33ea","signature":"export const Protected = () => ;"},{"anchor":"S:e80517f20b","kind":"interface","line":6,"name":"ActivationCheck","path_id":"F:14edab923f","signature":"export interface ActivationCheck"},{"anchor":"S:30eded078f","kind":"interface","line":17,"name":"ActivationLadderProps","path_id":"F:14edab923f","signature":"export interface ActivationLadderProps"},{"anchor":"S:73a3da9f65","doc":"The activation ladder: the three-rung progression from Disabled to Dry-run to Armed, * paired with the armed-mode gate checklist. Arming is only allowed when every * prerequisite holds. Items marked o","kind":"function","line":46,"name":"ActivationLadder","path_id":"F:14edab923f","signature":"export function ActivationLadder("},{"anchor":"S:237d74cadf","kind":"function","line":21,"name":"parseScalar","path_id":"F:1575110130","signature":"function parseScalar(raw)"},{"anchor":"S:299c43d83e","kind":"function","line":40,"name":"stripQuotes","path_id":"F:1575110130","signature":"function stripQuotes(s)"},{"anchor":"S:0b7b39d873","doc":"Parse a raw value string from after the colon, handling inline comments and quoted strings. Returns the trimmed scalar text or empty string.","kind":"function","line":49,"name":"extractRawValue","path_id":"F:1575110130","signature":"function extractRawValue(afterColon)"},{"anchor":"S:b4a3093fe9","doc":"Count leading spaces to determine nesting depth.","kind":"function","line":66,"name":"indentOf","path_id":"F:1575110130","signature":"function indentOf(line)"},{"anchor":"S:bec355e18a","doc":"Parse an array of non-empty, non-comment lines into a nested object. Each entry is { indent, key, rawValue, isItem }, where a sequence-item line (\"- value\") has isItem: true and key: null.","kind":"function","line":75,"name":"parseEntries","path_id":"F:1575110130","signature":"function parseEntries(entries, start, minIndent)"},{"anchor":"S:8990e6571f","kind":"function","line":118,"name":"parseFlatYaml","path_id":"F:1575110130","signature":"export function parseFlatYaml(text)"},{"anchor":"S:5bac9ae6d5","kind":"function","line":151,"name":"formatScalarForYaml","path_id":"F:1575110130","signature":"function formatScalarForYaml(value)"},{"anchor":"S:efe9cb11d4","doc":"Patch one or more top-level (zero-indent) scalar keys in a config.yaml's raw text, line by line. Every other line, including every comment, is left untouched, so a hand-written config file survives an","kind":"function","line":162,"name":"patchTopLevelYaml","path_id":"F:1575110130","signature":"export function patchTopLevelYaml(text, patch)"},{"anchor":"S:0b56ac32a5","kind":"const","line":1,"name":"MESSAGES","path_id":"F:179564da6f","signature":"export const MESSAGES ="},{"anchor":"S:1b14fa60f7","kind":"function","line":92,"name":"git","path_id":"F:18f569225a","signature":"function git(args, cwd)"},{"anchor":"S:34df99c630","kind":"function","line":98,"name":"makeGitFixture","path_id":"F:18f569225a","signature":"function makeGitFixture()"},{"anchor":"S:a3cae87964","kind":"function","line":109,"name":"makePlan","path_id":"F:18f569225a","signature":"function makePlan(role, roleDescriptor, transcriptSubdir, extra = {})"},{"anchor":"S:0eec918c49","kind":"function","line":116,"name":"cleanupTranscripts","path_id":"F:18f569225a","signature":"function cleanupTranscripts()"},{"anchor":"S:0064b473e6","kind":"function","line":14,"name":"tmpQueue","path_id":"F:195e9217ca","signature":"function tmpQueue()"},{"anchor":"S:d240732a9d","kind":"function","line":18,"name":"sampleAction","path_id":"F:195e9217ca","signature":"function sampleAction(id, target = \"ci\")"},{"anchor":"S:05a5299b28","kind":"interface","line":5,"name":"ConceptTileProps","path_id":"F:1a137480ae","signature":"export interface ConceptTileProps extends ButtonHTMLAttributes"},{"anchor":"S:14c08c7efc","doc":"A compact, focusable tile naming one engine concept: an icon, its name, and a short * category tag. Renders as a real button so it is keyboard-reachable on its own, meant * to be wrapped in a HoverCar","kind":"function","line":20,"name":"ConceptTile","path_id":"F:1a137480ae","signature":"export function ConceptTile({ icon, label, tag, className, ...rest }: ConceptTileProps)"},{"anchor":"S:76d7b21daf","doc":"Today's real high-water mark is 7 (Arming & Safety, Caps & budget tab). The budget is set a few above that: a real ratchet against regression, not an arbitrary ceiling.","kind":"const","line":18,"name":"MAX_CONTROLS_PER_TAB","path_id":"F:1a19f02364","signature":"export const MAX_CONTROLS_PER_TAB = 10;"},{"anchor":"S:b840cddd67","kind":"function","line":20,"name":"readScreens","path_id":"F:1a19f02364","signature":"function readScreens(root)"},{"anchor":"S:7a05eaea5a","doc":"Every field in config.schema.json must resolve to either a literal reference in a screen (a real control, or read-only display) or a documented exemption in exposure.json. A plain substring search, no","kind":"function","line":34,"name":"auditCoverage","path_id":"F:1a19f02364","signature":"export function auditCoverage(root)"},{"anchor":"S:da2f845458","doc":"Splits a screen's source into one segment per tab (by source order, using the `{tab === \"id\" ?` marker this codebase's tabbed screens consistently use), or a single whole-file segment for screens with","kind":"function","line":57,"name":"splitByTabs","path_id":"F:1a19f02364","signature":"function splitByTabs(text)"},{"anchor":"S:6a7737bb57","kind":"function","line":66,"name":"extractTags","path_id":"F:1a19f02364","signature":"function extractTags(text, tagNames)"},{"anchor":"S:0ac24bec51","doc":"Two checks, both numeric: a screen/tab must not exceed the control-density budget, and every value-entry control (Toggle, NumberField, Slider, Select) must carry a hint. Input is excluded from the hin","kind":"function","line":76,"name":"auditCoherence","path_id":"F:1a19f02364","signature":"export function auditCoherence(root)"},{"anchor":"S:762b3eaf4a","kind":"function","line":17,"name":"Models","path_id":"F:1aa7cf650d","signature":"export const Models = () => ("},{"anchor":"S:8da618623d","kind":"function","line":18,"name":"headSha","path_id":"F:1bc6d1449f","signature":"function headSha()"},{"anchor":"S:fc01241f03","doc":"A config fixture with distinct maker/checker models and a models registry.","kind":"function","line":13,"name":"cfg","path_id":"F:1bcaaff9eb","signature":"function cfg(overrides = {})"},{"anchor":"S:55b15c0abb","doc":"A short, stable id from a string. Hex keeps it deterministic across platforms.","kind":"function","line":9,"name":"short","path_id":"F:1cf31c4792","signature":"function short(text, len = 10)"},{"anchor":"S:2e016b842d","kind":"function","line":13,"name":"fileAnchor","path_id":"F:1cf31c4792","signature":"export function fileAnchor(relPath)"},{"anchor":"S:00db09c5a8","kind":"function","line":17,"name":"symbolAnchor","path_id":"F:1cf31c4792","signature":"export function symbolAnchor(relPath, name)"},{"anchor":"S:ab79b43633","doc":"Build the path dictionary from walked files. Returns { paths, pathIdByPath } where `paths` is the serializable { id -> relPath } map and `pathIdByPath` is the reverse lookup callers use to reference p","kind":"function","line":24,"name":"buildPathDictionary","path_id":"F:1cf31c4792","signature":"export function buildPathDictionary(relPaths)"},{"anchor":"S:63613c3a63","doc":"Build the symbol dictionary from API entries. Each entry carries its anchor, owning path id, name, and line, so an anchor resolves to an exact location.","kind":"function","line":37,"name":"buildSymbolDictionary","path_id":"F:1cf31c4792","signature":"export function buildSymbolDictionary(apiEntries)"},{"anchor":"S:a3ca73d34c","doc":"Lifecycle status of a learning: staged for review, or promoted into a permanent gate.","kind":"type","line":6,"name":"LearningStatus","path_id":"F:1d03291691","signature":"export type LearningStatus = \"staged\" | \"promoted\";"},{"anchor":"S:6cbed7ff26","doc":"Plain data shape for a single learning surfaced by the system. Components in this * package define their own shape rather than importing app-level types, so this * interface is the contract a host app","kind":"interface","line":13,"name":"LearningSummary","path_id":"F:1d03291691","signature":"export interface LearningSummary"},{"anchor":"S:8b9971d92a","kind":"interface","line":30,"name":"LearningCardProps","path_id":"F:1d03291691","signature":"export interface LearningCardProps"},{"anchor":"S:d293a69125","doc":"A card summarizing a single learning the system has surfaced: the lesson learned, * how old it is, what signal or evidence produced it, and its lifecycle status. * Staged learnings offer Promote and P","kind":"function","line":49,"name":"LearningCard","path_id":"F:1d03291691","signature":"export function LearningCard({ learning, onPromote, onPrune }: LearningCardProps)"},{"anchor":"S:14850052c8","kind":"interface","line":6,"name":"TabItem","path_id":"F:1db369d970","signature":"export interface TabItem"},{"anchor":"S:c68bb17ca2","kind":"interface","line":17,"name":"TabsProps","path_id":"F:1db369d970","signature":"export interface TabsProps"},{"anchor":"S:bd1a0a35f8","doc":"An accessible horizontal tab list. Implements the WAI-ARIA tabs pattern: the * container carries `role=\"tablist\"`, each tab carries `role=\"tab\"` and * `aria-selected`, and only the active tab is in th","kind":"function","line":35,"name":"Tabs","path_id":"F:1db369d970","signature":"export function Tabs({ tabs, active, onChange, className }: TabsProps)"},{"anchor":"S:d737cd7277","kind":"function","line":52,"name":"flagValue","path_id":"F:1e5ef6ba70","signature":"function flagValue(argv, name)"},{"anchor":"S:8f93f4689a","doc":"Resolve the full arming posture. Config values are advisory; the MODONOME_ARMED environment variable is authoritative (ADR-004). The capability flag layers ADR-024: even an armed engine will not rewri","kind":"function","line":60,"name":"armState","path_id":"F:1e5ef6ba70","signature":"function armState(root, env = process.env)"},{"anchor":"S:46d884501c","kind":"function","line":75,"name":"armingBlockers","path_id":"F:1e5ef6ba70","signature":"function armingBlockers(arm)"},{"anchor":"S:baa16abe42","kind":"function","line":84,"name":"targetIdentity","path_id":"F:1e5ef6ba70","signature":"function targetIdentity(argv)"},{"anchor":"S:6140d7ae56","kind":"function","line":90,"name":"identityUsable","path_id":"F:1e5ef6ba70","signature":"function identityUsable(id)"},{"anchor":"S:edeb959111","doc":"Gather the branch-unique commit range oldest-first with the fields the applier needs: tree object, first parent, author and committer identity and dates, and raw message. Enforces the protected-histor","kind":"function","line":97,"name":"gatherRange","path_id":"F:1e5ef6ba70","signature":"function gatherRange()"},{"anchor":"S:4bc9723575","doc":"Advisory range for `plan`: tolerant of a missing origin/main so the proposal works in a fresh clone. Newest-first from git log; reversed to oldest-first for stable output.","kind":"function","line":121,"name":"advisoryRange","path_id":"F:1e5ef6ba70","signature":"function advisoryRange()"},{"anchor":"S:59807c1a98","kind":"function","line":134,"name":"buildPlan","path_id":"F:1e5ef6ba70","signature":"function buildPlan(branch, commits, identity)"},{"anchor":"S:2484ffb006","kind":"function","line":142,"name":"printPlan","path_id":"F:1e5ef6ba70","signature":"function printPlan(plan, identity)"},{"anchor":"S:e7f49cafe1","kind":"function","line":168,"name":"isDirtyTracked","path_id":"F:1e5ef6ba70","signature":"function isDirtyTracked()"},{"anchor":"S:e2861b1099","kind":"function","line":173,"name":"rollback","path_id":"F:1e5ef6ba70","signature":"function rollback(savedHead)"},{"anchor":"S:e8b27564c5","doc":"Replay the range from the first changed commit forward, reusing each original tree object so the rewrite is metadata-only. Verifies tree-SHA invariance per commit and rolls back on any failure. Return","kind":"function","line":180,"name":"applyPlan","path_id":"F:1e5ef6ba70","signature":"function applyPlan(commits, plan)"},{"anchor":"S:b97efe3854","kind":"function","line":232,"name":"cmdPlan","path_id":"F:1e5ef6ba70","signature":"function cmdPlan(argv)"},{"anchor":"S:69db4ad7cc","kind":"function","line":244,"name":"cmdApply","path_id":"F:1e5ef6ba70","signature":"function cmdApply(argv, root)"},{"anchor":"S:602e030d27","kind":"function","line":297,"name":"main","path_id":"F:1e5ef6ba70","signature":"function main(argv)"},{"anchor":"S:5a6c3aef24","kind":"class","line":7,"name":"OrderService","path_id":"F:1ecd18c4b9","signature":"export class OrderService"},{"anchor":"S:a2fef04067","kind":"function","line":4,"name":"Budget","path_id":"F:1f40b6eb6e","signature":"export const Budget = () => ("},{"anchor":"S:2ed4ecfad7","kind":"const","line":1,"name":"MESSAGES","path_id":"F:1ff2bf39a4","signature":"export const MESSAGES ="},{"anchor":"S:8c2cd9c54f","doc":"The proposal text is fenced and framed as untrusted data, so a proposal cannot prompt-inject the checker into approving itself. Same hardening as review-diff.mjs.","kind":"function","line":26,"name":"buildProposalReviewPrompt","path_id":"F:2127a8caca","signature":"export function buildProposalReviewPrompt(proposal, checkerModel, authorLabel)"},{"anchor":"S:ebd259dfef","doc":"Resolve the checker and plan its review of a proposal, without calling a model. * * @returns {{ checker: object, authorLabel: string, proposal: string, prompt: string }}","kind":"function","line":43,"name":"planProposalReview","path_id":"F:2127a8caca","signature":"export function planProposalReview(cfg, { proposal, authorLabel = \"an external author\" } = {})"},{"anchor":"S:a1cc5660fe","doc":"A garbled review, or one with no explicit marker, must NOT read as an approval: a proposal is admitted to the backlog only on an explicit APPROVE: yes. Fail closed.","kind":"function","line":56,"name":"parseProposalVerdict","path_id":"F:2127a8caca","signature":"export function parseProposalVerdict(text)"},{"anchor":"S:3fc87c5f7e","doc":"Plan the proposal review and, under execute:true, run the checker on its endpoint. * The live path supports the openai-http transport (a local or free/gateway model), * matching the local-first cost s","kind":"function","line":73,"name":"reviewProposal","path_id":"F:2127a8caca","signature":"export async function reviewProposal(cfg, { proposal, authorLabel, execute = false } = {}, deps = {})"},{"anchor":"S:537ea4dfe0","kind":"type","line":5,"name":"ToggleTone","path_id":"F:214cc0a5f4","signature":"export type ToggleTone = \"primary\" | \"info\" | \"owner\";"},{"anchor":"S:cd836c2fc7","kind":"interface","line":7,"name":"ToggleProps","path_id":"F:214cc0a5f4","signature":"export interface ToggleProps"},{"anchor":"S:84b00e90de","doc":"An accessible switch for boolean config such as dry_run, auto_merge, or * local_model_only_by_default. Implemented as a `role=\"switch\"` button rather * than a checkbox so the on/off semantics are anno","kind":"function","line":28,"name":"Toggle","path_id":"F:214cc0a5f4","signature":"export function Toggle("},{"anchor":"S:b919653baa","kind":"function","line":44,"name":"DryRun","path_id":"F:2207a6ebce","signature":"export const DryRun = () => ("},{"anchor":"S:ea5d04ea13","kind":"function","line":48,"name":"Armed","path_id":"F:2207a6ebce","signature":"export const Armed = () => ("},{"anchor":"S:e193570e9e","kind":"const","line":1,"name":"MESSAGES","path_id":"F:2215d0e1fc","signature":"export const MESSAGES ="},{"anchor":"S:7cd45cbc03","kind":"function","line":62,"name":"formatYamlScalar","path_id":"F:22566cb46e","signature":"function formatYamlScalar(value)"},{"anchor":"S:1c5d801590","doc":"A line-level patch, not a full YAML re-serialize, so every hand-written comment in config.yaml survives an edit made from the panel. Only top-level, zero-indent scalar or array keys are touched here; ","kind":"function","line":70,"name":"patchYamlText","path_id":"F:22566cb46e","signature":"function patchYamlText(text, patch)"},{"anchor":"S:15b3a95566","doc":"Locate a top-level `key:` block-opening line (a zero-indent key whose value is empty, meaning what follows is a nested map) and the half-open [start, end) line range it and its indented content occupy","kind":"function","line":100,"name":"findBlock","path_id":"F:22566cb46e","signature":"function findBlock(lines, key)"},{"anchor":"S:aa8f9a7b3d","doc":"Split a block's interior lines into ordered segments: a real entry (a line at exactly ENTRY_INDENT spaces naming a key, plus every following line indented deeper than that), or \"other\" (blank lines, a","kind":"function","line":122,"name":"captureSegments","path_id":"F:22566cb46e","signature":"function captureSegments(lines, start, end)"},{"anchor":"S:c3a1d0f1a7","kind":"function","line":151,"name":"serializeEntry","path_id":"F:22566cb46e","signature":"function serializeEntry(topKey, entryKey, value)"},{"anchor":"S:af28852c7f","kind":"function","line":169,"name":"deepEqualJson","path_id":"F:22566cb46e","signature":"function deepEqualJson(a, b)"},{"anchor":"S:2eef7d840d","doc":"Reconcile one nested map's block against its new value, entry by entry. An entry present in both, unchanged, is copied verbatim (comments and all); a changed entry is re-serialized (dropping any comme","kind":"function","line":180,"name":"rewriteBlock","path_id":"F:22566cb46e","signature":"function rewriteBlock(lines, topKey, oldValue, newValue)"},{"anchor":"S:b06714d9c5","kind":"function","line":225,"name":"patchConfig","path_id":"F:22566cb46e","signature":"export function patchConfig(modonomeDir, patch)"},{"anchor":"S:8b67ef3e8b","kind":"function","line":266,"name":"workItemFile","path_id":"F:22566cb46e","signature":"function workItemFile(modonomeDir, itemId)"},{"anchor":"S:fd9d32de9a","kind":"function","line":272,"name":"releaseLease","path_id":"F:22566cb46e","signature":"export function releaseLease(modonomeDir, itemId)"},{"anchor":"S:d7086f2a5b","kind":"function","line":300,"name":"loadConfigForValidation","path_id":"F:22566cb46e","signature":"function loadConfigForValidation(modonomeDir)"},{"anchor":"S:f22a53ac17","kind":"function","line":305,"name":"createWorkItem","path_id":"F:22566cb46e","signature":"export function createWorkItem(modonomeDir, input)"},{"anchor":"S:a4e623c70b","doc":"Metadata-only edit: type, assigned_role, allowed_edit_set, gates, max_attempts, and touches_protected_path are safe to change regardless of the item's current state, including in flight, since none of","kind":"function","line":354,"name":"updateWorkItem","path_id":"F:22566cb46e","signature":"export function updateWorkItem(modonomeDir, itemId, patch)"},{"anchor":"S:14cb0e8cbb","doc":"Refuses outright for any in-flight state, regardless of whether its lease has technically expired: an item past \"queued\" represents real record of what happened (a branch, a PR, attempts, a maker iden","kind":"function","line":377,"name":"deleteWorkItem","path_id":"F:22566cb46e","signature":"export function deleteWorkItem(modonomeDir, itemId)"},{"anchor":"S:e152142e8c","doc":"Merge a patch of { id: { severity?, text?, suppressed? } } into .modonome/messages.yaml's overrides map, re-validate against both the schema and the severity-floor rule (the same checkOverridesIntegri","kind":"function","line":399,"name":"patchMessages","path_id":"F:22566cb46e","signature":"export function patchMessages(modonomeDir, patch)"},{"anchor":"S:5b0e153cfb","kind":"function","line":424,"name":"pruneLearning","path_id":"F:22566cb46e","signature":"export function pruneLearning(modonomeDir, lesson)"},{"anchor":"S:a931ad2e62","doc":"Concatenate the committed prompt source files into one searchable string. * @param {string} root repository root that contains the prompts directory * @returns {string} the concatenated committed prom","kind":"function","line":46,"name":"resolvePromptText","path_id":"F:23917c6197","signature":"export function resolvePromptText(root)"},{"anchor":"S:0a5fed1978","doc":"Load every fixture JSON file from a directory. * @param {string} dir directory holding fixture *.json files * @returns {Array