@groundnuty/macf 0.2.35 → 0.2.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-info.json +2 -2
- package/dist/cli/claude-sh.d.ts +12 -10
- package/dist/cli/claude-sh.d.ts.map +1 -1
- package/dist/cli/claude-sh.js +26 -13
- package/dist/cli/claude-sh.js.map +1 -1
- package/dist/cli/commands/certs.js +3 -3
- package/dist/cli/commands/certs.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +10 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/monitor.d.ts +16 -0
- package/dist/cli/commands/monitor.d.ts.map +1 -0
- package/dist/cli/commands/monitor.js +96 -0
- package/dist/cli/commands/monitor.js.map +1 -0
- package/dist/cli/commands/propose.d.ts +21 -0
- package/dist/cli/commands/propose.d.ts.map +1 -0
- package/dist/cli/commands/propose.js +128 -0
- package/dist/cli/commands/propose.js.map +1 -0
- package/dist/cli/commands/rules-refresh.d.ts +1 -0
- package/dist/cli/commands/rules-refresh.d.ts.map +1 -1
- package/dist/cli/commands/rules-refresh.js +22 -1
- package/dist/cli/commands/rules-refresh.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +23 -2
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/env-files-update.d.ts.map +1 -1
- package/dist/cli/env-files-update.js +5 -1
- package/dist/cli/env-files-update.js.map +1 -1
- package/dist/cli/env-files.d.ts +38 -13
- package/dist/cli/env-files.d.ts.map +1 -1
- package/dist/cli/env-files.js +73 -14
- package/dist/cli/env-files.js.map +1 -1
- package/dist/cli/index.js +109 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/monitor/digest.d.ts +89 -0
- package/dist/cli/monitor/digest.d.ts.map +1 -0
- package/dist/cli/monitor/digest.js +232 -0
- package/dist/cli/monitor/digest.js.map +1 -0
- package/dist/cli/monitor/github-reader.d.ts +38 -0
- package/dist/cli/monitor/github-reader.d.ts.map +1 -0
- package/dist/cli/monitor/github-reader.js +65 -0
- package/dist/cli/monitor/github-reader.js.map +1 -0
- package/dist/cli/monitor/reflections.d.ts +18 -0
- package/dist/cli/monitor/reflections.d.ts.map +1 -0
- package/dist/cli/monitor/reflections.js +72 -0
- package/dist/cli/monitor/reflections.js.map +1 -0
- package/dist/cli/monitor/run.d.ts +30 -0
- package/dist/cli/monitor/run.d.ts.map +1 -0
- package/dist/cli/monitor/run.js +67 -0
- package/dist/cli/monitor/run.js.map +1 -0
- package/dist/cli/project-rules.d.ts +105 -0
- package/dist/cli/project-rules.d.ts.map +1 -0
- package/dist/cli/project-rules.js +305 -0
- package/dist/cli/project-rules.js.map +1 -0
- package/dist/cli/propose/candidates.d.ts +95 -0
- package/dist/cli/propose/candidates.d.ts.map +1 -0
- package/dist/cli/propose/candidates.js +117 -0
- package/dist/cli/propose/candidates.js.map +1 -0
- package/dist/cli/propose/invariants.d.ts +49 -0
- package/dist/cli/propose/invariants.d.ts.map +1 -0
- package/dist/cli/propose/invariants.js +154 -0
- package/dist/cli/propose/invariants.js.map +1 -0
- package/dist/cli/propose/proposal-writer.d.ts +33 -0
- package/dist/cli/propose/proposal-writer.d.ts.map +1 -0
- package/dist/cli/propose/proposal-writer.js +53 -0
- package/dist/cli/propose/proposal-writer.js.map +1 -0
- package/dist/cli/propose/report.d.ts +49 -0
- package/dist/cli/propose/report.d.ts.map +1 -0
- package/dist/cli/propose/report.js +227 -0
- package/dist/cli/propose/report.js.map +1 -0
- package/dist/cli/propose/run.d.ts +41 -0
- package/dist/cli/propose/run.d.ts.map +1 -0
- package/dist/cli/propose/run.js +62 -0
- package/dist/cli/propose/run.js.map +1 -0
- package/dist/cli/settings-writer.d.ts +87 -6
- package/dist/cli/settings-writer.d.ts.map +1 -1
- package/dist/cli/settings-writer.js +141 -6
- package/dist/cli/settings-writer.js.map +1 -1
- package/dist/reconciler/parse-delivered.d.ts +32 -0
- package/dist/reconciler/parse-delivered.d.ts.map +1 -0
- package/dist/reconciler/parse-delivered.js +18 -0
- package/dist/reconciler/parse-delivered.js.map +1 -0
- package/dist/reconciler/parse-processed.d.ts +57 -0
- package/dist/reconciler/parse-processed.d.ts.map +1 -0
- package/dist/reconciler/parse-processed.js +41 -0
- package/dist/reconciler/parse-processed.js.map +1 -0
- package/dist/reconciler/reconcile.d.ts +130 -0
- package/dist/reconciler/reconcile.d.ts.map +1 -0
- package/dist/reconciler/reconcile.js +119 -0
- package/dist/reconciler/reconcile.js.map +1 -0
- package/dist/reconciler/run.d.ts +23 -0
- package/dist/reconciler/run.d.ts.map +1 -0
- package/dist/reconciler/run.js +273 -0
- package/dist/reconciler/run.js.map +1 -0
- package/package.json +2 -2
- package/plugin/rules/coordination.md +22 -13
- package/plugin/rules/gh-token-attribution-traps.md +4 -0
- package/plugin/rules/mention-routing-hygiene.md +2 -0
- package/plugin/rules/observability-wiring.md +3 -3
- package/plugin/rules/reflection-staging.md +65 -0
- package/plugin/rules/silent-fallback-hazards.md +64 -8
- package/scripts/check-auditor-never-acts.sh +167 -0
- package/scripts/check-gh-attribution.sh +230 -0
- package/scripts/emit-turn-receipt.sh +81 -0
- package/scripts/harvest-reflection.sh +125 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { invariantsTouched, readsAsRelaxation, } from './invariants.js';
|
|
2
|
+
/** Default distinct-agent threshold for promotion (configurable). */
|
|
3
|
+
export const DEFAULT_MIN_AGENTS = 2;
|
|
4
|
+
/** Tier values that must never auto-route (affect every deployment). */
|
|
5
|
+
const UNIVERSAL_TIERS = new Set(['universal', 'canonical']);
|
|
6
|
+
/** Group key: same handle proposed at two tiers → two distinct candidates. */
|
|
7
|
+
function groupKey(tier, handle) {
|
|
8
|
+
return JSON.stringify([tier, handle]);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Group all reflection rule-evolution signals by (proposed_tier, handle),
|
|
12
|
+
* accumulating the SET OF DISTINCT AGENT NAMES (not occurrences) for GATE 1.
|
|
13
|
+
*
|
|
14
|
+
* This is the load-bearing distinction from F4's `aggregateSignals`, which
|
|
15
|
+
* counts occurrences. Five signals from one agent collapse to a single-agent
|
|
16
|
+
* set here; five from five agents collapse to a five-agent set.
|
|
17
|
+
*/
|
|
18
|
+
function groupSignals(records) {
|
|
19
|
+
const byKey = new Map();
|
|
20
|
+
for (const rec of records) {
|
|
21
|
+
const agentName = rec.agent.name;
|
|
22
|
+
for (const sig of rec.rule_evolution_signals) {
|
|
23
|
+
const hasKey = typeof sig.key === 'string' && sig.key.length > 0;
|
|
24
|
+
const handle = hasKey ? sig.key : sig.signal;
|
|
25
|
+
const k = groupKey(sig.proposed_tier, handle);
|
|
26
|
+
let g = byKey.get(k);
|
|
27
|
+
if (!g) {
|
|
28
|
+
g = {
|
|
29
|
+
handle,
|
|
30
|
+
hasKey,
|
|
31
|
+
proposedTier: sig.proposed_tier,
|
|
32
|
+
signal: sig.signal,
|
|
33
|
+
agents: new Set(),
|
|
34
|
+
rationales: [],
|
|
35
|
+
occurrences: 0,
|
|
36
|
+
};
|
|
37
|
+
byKey.set(k, g);
|
|
38
|
+
}
|
|
39
|
+
g.agents.add(agentName);
|
|
40
|
+
g.occurrences += 1;
|
|
41
|
+
const rationale = sig.rationale.trim();
|
|
42
|
+
if (rationale.length > 0 && !g.rationales.includes(rationale)) {
|
|
43
|
+
g.rationales.push(rationale);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [...byKey.values()];
|
|
48
|
+
}
|
|
49
|
+
/** Route a candidate from its tier hint (universal/canonical never auto-route). */
|
|
50
|
+
export function routeForTier(proposedTier) {
|
|
51
|
+
const tier = proposedTier.trim().toLowerCase();
|
|
52
|
+
if (UNIVERSAL_TIERS.has(tier))
|
|
53
|
+
return 'needs-confirmation';
|
|
54
|
+
if (tier === 'project')
|
|
55
|
+
return 'project-draft';
|
|
56
|
+
return 'review';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run the full candidate pipeline over the reflection records.
|
|
60
|
+
*
|
|
61
|
+
* Steps (DR-026 G1 §The command):
|
|
62
|
+
* 1. Aggregate signals (distinct-agent grouping).
|
|
63
|
+
* 2. GATE 1 — keep candidates with distinctAgents ≥ minAgents; the rest go to
|
|
64
|
+
* `held` (visible, never silently dropped).
|
|
65
|
+
* 3. Tier-router — universal/canonical → needs-confirmation; project → draft.
|
|
66
|
+
* 4. Subordination-check — surface touched invariants + HIGH-RISK relaxation
|
|
67
|
+
* flag. NEVER drops (GATE 3).
|
|
68
|
+
*/
|
|
69
|
+
export function buildCandidates(records, invariants, minAgents = DEFAULT_MIN_AGENTS) {
|
|
70
|
+
const threshold = Number.isFinite(minAgents) && minAgents >= 1 ? Math.floor(minAgents) : DEFAULT_MIN_AGENTS;
|
|
71
|
+
const groups = groupSignals(records);
|
|
72
|
+
const promoted = [];
|
|
73
|
+
const held = [];
|
|
74
|
+
for (const g of groups) {
|
|
75
|
+
const distinctAgents = g.agents.size;
|
|
76
|
+
if (distinctAgents < threshold) {
|
|
77
|
+
held.push({
|
|
78
|
+
handle: g.handle,
|
|
79
|
+
hasKey: g.hasKey,
|
|
80
|
+
proposedTier: g.proposedTier,
|
|
81
|
+
signal: g.signal,
|
|
82
|
+
distinctAgents,
|
|
83
|
+
occurrences: g.occurrences,
|
|
84
|
+
reason: `N=${distinctAgents} distinct agent(s) < threshold ${threshold} (reflection ≠ verification)`,
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Step 4 — subordination-check surfacing (GATE 3: surface, never drop).
|
|
89
|
+
const candidateText = [g.signal, ...g.rationales].join('\n');
|
|
90
|
+
const touches = invariantsTouched(candidateText, invariants);
|
|
91
|
+
const highRisk = readsAsRelaxation(candidateText) && touches.length > 0;
|
|
92
|
+
promoted.push({
|
|
93
|
+
handle: g.handle,
|
|
94
|
+
hasKey: g.hasKey,
|
|
95
|
+
proposedTier: g.proposedTier,
|
|
96
|
+
signal: g.signal,
|
|
97
|
+
rationales: g.rationales,
|
|
98
|
+
corroboratingAgents: [...g.agents].sort(),
|
|
99
|
+
distinctAgents,
|
|
100
|
+
occurrences: g.occurrences,
|
|
101
|
+
route: routeForTier(g.proposedTier),
|
|
102
|
+
invariantTouches: touches,
|
|
103
|
+
highRisk,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Strongest corroboration first, then high-risk surfaced near the top so the
|
|
107
|
+
// operator sees the constitutional-scrutiny candidates early.
|
|
108
|
+
promoted.sort((a, b) => Number(b.highRisk) - Number(a.highRisk) ||
|
|
109
|
+
b.distinctAgents - a.distinctAgents ||
|
|
110
|
+
a.proposedTier.localeCompare(b.proposedTier) ||
|
|
111
|
+
a.handle.localeCompare(b.handle));
|
|
112
|
+
held.sort((a, b) => b.distinctAgents - a.distinctAgents ||
|
|
113
|
+
a.proposedTier.localeCompare(b.proposedTier) ||
|
|
114
|
+
a.handle.localeCompare(b.handle));
|
|
115
|
+
return { minAgents: threshold, promoted, held };
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=candidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/cli/propose/candidates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** One protected invariant, parsed from the ratified design doc. */
|
|
2
|
+
export interface ProtectedInvariant {
|
|
3
|
+
/** 1-based ordinal as it appears in the doc. */
|
|
4
|
+
readonly index: number;
|
|
5
|
+
/** Short bold title (the text before the first period of the list item). */
|
|
6
|
+
readonly title: string;
|
|
7
|
+
/** The full list-item line (title + gloss + refs). */
|
|
8
|
+
readonly text: string;
|
|
9
|
+
/** Lowercased keyword tokens used for the heuristic touch-match. */
|
|
10
|
+
readonly keywords: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/** A surfaced touchpoint: which invariant a candidate plausibly touches. */
|
|
13
|
+
export interface InvariantTouch {
|
|
14
|
+
readonly index: number;
|
|
15
|
+
readonly title: string;
|
|
16
|
+
/** Tokens that matched (for operator transparency). */
|
|
17
|
+
readonly matchedKeywords: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse the invariant list out of `protected-invariants.md`.
|
|
21
|
+
*
|
|
22
|
+
* The doc's invariants are an ordered Markdown list, each item shaped like:
|
|
23
|
+
* `1. **Reporter-owns-closure accountability.** The agent who ... (refs)`
|
|
24
|
+
* We extract the bold title, the full line, and a keyword set (title words minus
|
|
25
|
+
* stopwords, plus the curated set for that ordinal).
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseInvariants(markdown: string): readonly ProtectedInvariant[];
|
|
28
|
+
/**
|
|
29
|
+
* Load the protected-invariant set from the repo's `design/protected-invariants.md`.
|
|
30
|
+
*
|
|
31
|
+
* `repoRoot` is the framework-source repo root (where `design/` lives). Returns
|
|
32
|
+
* `[]` (never throws) when the file is absent — the membrane still runs and the
|
|
33
|
+
* subordination-check simply surfaces nothing (loud-but-proceeds). A missing
|
|
34
|
+
* invariant file is surfaced separately by the caller.
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadInvariants(repoRoot: string): readonly ProtectedInvariant[];
|
|
37
|
+
/**
|
|
38
|
+
* For a candidate's combined text, return which invariants it plausibly touches.
|
|
39
|
+
*
|
|
40
|
+
* A touch is recorded when ANY of the invariant's keywords appears (as a
|
|
41
|
+
* substring) in the candidate text. Generous by design (see module header).
|
|
42
|
+
*/
|
|
43
|
+
export declare function invariantsTouched(candidateText: string, invariants: readonly ProtectedInvariant[]): readonly InvariantTouch[];
|
|
44
|
+
/**
|
|
45
|
+
* Whether the candidate text reads like it RELAXES a guarantee. Heuristic only —
|
|
46
|
+
* a `true` here means "flag HIGH-RISK for operator scrutiny", NOT "drop".
|
|
47
|
+
*/
|
|
48
|
+
export declare function readsAsRelaxation(candidateText: string): boolean;
|
|
49
|
+
//# sourceMappingURL=invariants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants.d.ts","sourceRoot":"","sources":["../../../src/cli/propose/invariants.ts"],"names":[],"mappings":"AAuBA,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAgCD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAmB/E;AAkCD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAU9E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,SAAS,kBAAkB,EAAE,GACxC,SAAS,cAAc,EAAE,CAU3B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAEhE"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protected-invariant loader + subordination-check heuristics for the auditor
|
|
3
|
+
* Plan membrane (groundnuty/macf#503, DR-026 G1).
|
|
4
|
+
*
|
|
5
|
+
* Loads `design/protected-invariants.md` (the ratified SECP guardrail core) and
|
|
6
|
+
* surfaces, for a given candidate's text, WHICH invariant(s) it plausibly
|
|
7
|
+
* touches and whether the text *reads like* a relaxation of one.
|
|
8
|
+
*
|
|
9
|
+
* CRITICAL — this module SURFACES; it never decides. `protected-invariants.md`
|
|
10
|
+
* carries an amendment clause: the auditor may *propose* an operator-ratified
|
|
11
|
+
* amendment to an invariant, so auto-dropping a candidate that touches one would
|
|
12
|
+
* foreclose that constitutional path. We therefore mark — never reject. The
|
|
13
|
+
* weaken-vs-amend call is the operator's (v1-manual) and, later, G3's.
|
|
14
|
+
*
|
|
15
|
+
* The match is a deliberately simple keyword/heuristic pass on the invariant
|
|
16
|
+
* titles + a small curated keyword set per invariant. It is intentionally
|
|
17
|
+
* generous (favours surfacing a touch over missing one): a false-positive
|
|
18
|
+
* "touches invariant N" is cheap (operator eyeballs it), a false-negative is the
|
|
19
|
+
* dangerous direction.
|
|
20
|
+
*/
|
|
21
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
/**
|
|
24
|
+
* Per-invariant curated keyword sets. Keyed by the 1-based ordinal in
|
|
25
|
+
* `protected-invariants.md`. These augment the auto-extracted title words so the
|
|
26
|
+
* touch-match catches paraphrases the title alone would miss (e.g. "merge"
|
|
27
|
+
* mapping to the LGTM-gate invariant). Lowercase, matched as word-ish substrings.
|
|
28
|
+
*/
|
|
29
|
+
const CURATED_KEYWORDS = {
|
|
30
|
+
1: ['reporter', 'closure', 'close', 'owns', 'verify', 'verification'],
|
|
31
|
+
2: ['identity', 'attribution', 'attributed', 'bot', 'token', 'impersonat'],
|
|
32
|
+
3: ['merge', 'self-merge', 'lgtm', 'approve', 'approved', 'review', 'non-author'],
|
|
33
|
+
4: ['routing', 'route', 'mention', '@mention', 'recipient', 'false-route'],
|
|
34
|
+
5: ['auto-close', 'closes', 'fixes', 'resolves', 'refs', 'keyword'],
|
|
35
|
+
6: ['fail-loud', 'silent', 'fallback', 'result-invariant', 'exit code', 'assert'],
|
|
36
|
+
7: ['pr', 'pull request', 'artifact', 'rollback', 'review', 'ci'],
|
|
37
|
+
8: ['auditor', 'never-acts', 'propose', 'proposes', 'merge', 'close', 'implement', 'act'],
|
|
38
|
+
9: ['operator', 'ratifier', 'ratify', 'ratification', 'auto-applied', 'constitutional', 'human'],
|
|
39
|
+
10: ['universal', 'locally', 'local', 'mutable', 'patch', 'upstream', 'product rule'],
|
|
40
|
+
};
|
|
41
|
+
/** Words too generic to be a meaningful touch-signal on their own. */
|
|
42
|
+
const STOPWORDS = new Set([
|
|
43
|
+
'the', 'and', 'for', 'with', 'not', 'never', 'over', 'must', 'any',
|
|
44
|
+
'every', 'that', 'this', 'its', 'are', 'all', 'who', 'how', 'a', 'an',
|
|
45
|
+
'is', 'to', 'of', 'or', 'on', 'by', 'be', 'it', 'as', 'no',
|
|
46
|
+
]);
|
|
47
|
+
/** Phrases in candidate text that read like a *relaxation* of a guarantee. */
|
|
48
|
+
const RELAXATION_HINT = /\b(?:relax|weaken|loosen|drop|remove|skip|bypass|disable|waive|exempt|optional(?:ly)?|allow(?:ed|s)?\s+(?:self|auto|without)|no\s+longer\s+(?:require|need)|without\s+(?:a\s+)?(?:review|approval|mention|token)|self-merge|auto-merge|auto-close)\b/i;
|
|
49
|
+
/**
|
|
50
|
+
* Parse the invariant list out of `protected-invariants.md`.
|
|
51
|
+
*
|
|
52
|
+
* The doc's invariants are an ordered Markdown list, each item shaped like:
|
|
53
|
+
* `1. **Reporter-owns-closure accountability.** The agent who ... (refs)`
|
|
54
|
+
* We extract the bold title, the full line, and a keyword set (title words minus
|
|
55
|
+
* stopwords, plus the curated set for that ordinal).
|
|
56
|
+
*/
|
|
57
|
+
export function parseInvariants(markdown) {
|
|
58
|
+
const out = [];
|
|
59
|
+
// Only parse list items under the "## The invariants" section, so the
|
|
60
|
+
// "## Amending this set" numbered list (1./2./3.) is not mistaken for invariants.
|
|
61
|
+
const section = sliceInvariantSection(markdown);
|
|
62
|
+
const itemRe = /^(\d+)\.\s+\*\*(.+?)\*\*\s*(.*)$/;
|
|
63
|
+
for (const rawLine of section.split('\n')) {
|
|
64
|
+
const line = rawLine.trim();
|
|
65
|
+
const m = itemRe.exec(line);
|
|
66
|
+
if (!m)
|
|
67
|
+
continue;
|
|
68
|
+
const index = Number(m[1]);
|
|
69
|
+
const title = (m[2] ?? '').replace(/\.$/, '').trim();
|
|
70
|
+
const text = line;
|
|
71
|
+
const titleTokens = tokenize(title);
|
|
72
|
+
const curated = CURATED_KEYWORDS[index] ?? [];
|
|
73
|
+
const keywords = [...new Set([...titleTokens, ...curated.map((k) => k.toLowerCase())])];
|
|
74
|
+
out.push({ index, title, text, keywords });
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Slice the markdown to the "## The invariants" section only (up to the next
|
|
80
|
+
* `## ` heading). Falls back to the whole doc if the heading isn't found.
|
|
81
|
+
*/
|
|
82
|
+
function sliceInvariantSection(markdown) {
|
|
83
|
+
const lines = markdown.split('\n');
|
|
84
|
+
let start = -1;
|
|
85
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
86
|
+
if (/^##\s+The invariants\s*$/i.test(lines[i].trim())) {
|
|
87
|
+
start = i + 1;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (start < 0)
|
|
92
|
+
return markdown;
|
|
93
|
+
let end = lines.length;
|
|
94
|
+
for (let i = start; i < lines.length; i += 1) {
|
|
95
|
+
if (/^##\s+/.test(lines[i].trim())) {
|
|
96
|
+
end = i;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return lines.slice(start, end).join('\n');
|
|
101
|
+
}
|
|
102
|
+
function tokenize(s) {
|
|
103
|
+
return s
|
|
104
|
+
.toLowerCase()
|
|
105
|
+
.split(/[^a-z0-9-]+/)
|
|
106
|
+
.map((t) => t.trim())
|
|
107
|
+
.filter((t) => t.length >= 3 && !STOPWORDS.has(t));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Load the protected-invariant set from the repo's `design/protected-invariants.md`.
|
|
111
|
+
*
|
|
112
|
+
* `repoRoot` is the framework-source repo root (where `design/` lives). Returns
|
|
113
|
+
* `[]` (never throws) when the file is absent — the membrane still runs and the
|
|
114
|
+
* subordination-check simply surfaces nothing (loud-but-proceeds). A missing
|
|
115
|
+
* invariant file is surfaced separately by the caller.
|
|
116
|
+
*/
|
|
117
|
+
export function loadInvariants(repoRoot) {
|
|
118
|
+
const path = join(repoRoot, 'design', 'protected-invariants.md');
|
|
119
|
+
if (!existsSync(path))
|
|
120
|
+
return [];
|
|
121
|
+
let raw;
|
|
122
|
+
try {
|
|
123
|
+
raw = readFileSync(path, 'utf-8');
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
return parseInvariants(raw);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* For a candidate's combined text, return which invariants it plausibly touches.
|
|
132
|
+
*
|
|
133
|
+
* A touch is recorded when ANY of the invariant's keywords appears (as a
|
|
134
|
+
* substring) in the candidate text. Generous by design (see module header).
|
|
135
|
+
*/
|
|
136
|
+
export function invariantsTouched(candidateText, invariants) {
|
|
137
|
+
const hay = candidateText.toLowerCase();
|
|
138
|
+
const touches = [];
|
|
139
|
+
for (const inv of invariants) {
|
|
140
|
+
const matched = inv.keywords.filter((k) => hay.includes(k));
|
|
141
|
+
if (matched.length > 0) {
|
|
142
|
+
touches.push({ index: inv.index, title: inv.title, matchedKeywords: matched });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return touches;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Whether the candidate text reads like it RELAXES a guarantee. Heuristic only —
|
|
149
|
+
* a `true` here means "flag HIGH-RISK for operator scrutiny", NOT "drop".
|
|
150
|
+
*/
|
|
151
|
+
export function readsAsRelaxation(candidateText) {
|
|
152
|
+
return RELAXATION_HINT.test(candidateText);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=invariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants.js","sourceRoot":"","sources":["../../../src/cli/propose/invariants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** The label every auditor-opened proposal issue carries (for filtering). */
|
|
2
|
+
export declare const PROPOSAL_LABEL = "auditor-proposal";
|
|
3
|
+
/** Input to open a single ratifiable proposal issue. */
|
|
4
|
+
export interface ProposalIssueInput {
|
|
5
|
+
readonly repo: string;
|
|
6
|
+
readonly title: string;
|
|
7
|
+
/** The full Markdown proposal body (assembled from agent-authored content). */
|
|
8
|
+
readonly body: string;
|
|
9
|
+
/** Labels to apply on creation; always includes `auditor-proposal`. */
|
|
10
|
+
readonly labels: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/** Result of opening a proposal issue. */
|
|
13
|
+
export interface ProposalIssueResult {
|
|
14
|
+
/** The created issue URL (or number) as returned by the creator. */
|
|
15
|
+
readonly url: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The create-only GitHub seam. Implementations MUST perform only issue
|
|
19
|
+
* CREATION. The membrane depends on this interface (not on `gh` directly) so
|
|
20
|
+
* tests can inject a fake + assert (a) zero creates in dry-run mode and (b)
|
|
21
|
+
* create-only behaviour under `--file`.
|
|
22
|
+
*/
|
|
23
|
+
export interface ProposalIssueWriter {
|
|
24
|
+
createProposalIssue(input: ProposalIssueInput): Promise<ProposalIssueResult>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Production writer: shells out to `gh issue create` for a SINGLE issue per
|
|
28
|
+
* call. `token` is forwarded as `GH_TOKEN` in the subprocess env (canonical bot
|
|
29
|
+
* auth). This class has no merge/close/edit/comment path at all — issue creation
|
|
30
|
+
* is the only operation it can perform.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createGhProposalWriter(token: string): ProposalIssueWriter;
|
|
33
|
+
//# sourceMappingURL=proposal-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal-writer.d.ts","sourceRoot":"","sources":["../../../src/cli/propose/proposal-writer.ts"],"names":[],"mappings":"AA0BA,6EAA6E;AAC7E,eAAO,MAAM,cAAc,qBAAqB,CAAC;AAEjD,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC9E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAwBzE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create-only GitHub seam for the auditor Plan membrane
|
|
3
|
+
* (groundnuty/macf#503, DR-026 G1).
|
|
4
|
+
*
|
|
5
|
+
* THE LOAD-BEARING INVARIANT (mirror of F4's read-only `GitHubReader`, inverted
|
|
6
|
+
* for creation): the Plan membrane may, under an explicit `--file` flag, OPEN
|
|
7
|
+
* ratifiable proposal artifacts — but it may do NOTHING else. This interface
|
|
8
|
+
* exposes ONLY `createProposalIssue`. There is deliberately NO merge / close /
|
|
9
|
+
* edit / comment / label-mutate / delete method on the seam, so any
|
|
10
|
+
* non-proposal mutation is *unrepresentable* through the type. This is invariant
|
|
11
|
+
* #8 (auditor-never-acts) enforced structurally at the type boundary: the
|
|
12
|
+
* auditor proposes, the operator ratifies — the auditor can never apply.
|
|
13
|
+
*
|
|
14
|
+
* The default implementation shells out to `gh issue create` via `execFile` (a
|
|
15
|
+
* single create per candidate, with the `auditor-proposal` label). The token is
|
|
16
|
+
* passed via `GH_TOKEN` in the subprocess env (the house bot-auth posture),
|
|
17
|
+
* never baked into a remote or used for any other op.
|
|
18
|
+
*
|
|
19
|
+
* Tests inject a fake implementation and assert it received CREATES only (and
|
|
20
|
+
* zero creates in the default dry-run mode).
|
|
21
|
+
*/
|
|
22
|
+
import { execFile } from 'node:child_process';
|
|
23
|
+
import { promisify } from 'node:util';
|
|
24
|
+
const execFileAsync = promisify(execFile);
|
|
25
|
+
/** The label every auditor-opened proposal issue carries (for filtering). */
|
|
26
|
+
export const PROPOSAL_LABEL = 'auditor-proposal';
|
|
27
|
+
/**
|
|
28
|
+
* Production writer: shells out to `gh issue create` for a SINGLE issue per
|
|
29
|
+
* call. `token` is forwarded as `GH_TOKEN` in the subprocess env (canonical bot
|
|
30
|
+
* auth). This class has no merge/close/edit/comment path at all — issue creation
|
|
31
|
+
* is the only operation it can perform.
|
|
32
|
+
*/
|
|
33
|
+
export function createGhProposalWriter(token) {
|
|
34
|
+
const env = { ...process.env, GH_TOKEN: token };
|
|
35
|
+
return {
|
|
36
|
+
async createProposalIssue(input) {
|
|
37
|
+
const labelArgs = [];
|
|
38
|
+
for (const label of input.labels) {
|
|
39
|
+
labelArgs.push('--label', label);
|
|
40
|
+
}
|
|
41
|
+
const { stdout } = await execFileAsync('gh', [
|
|
42
|
+
'issue', 'create',
|
|
43
|
+
'--repo', input.repo,
|
|
44
|
+
'--title', input.title,
|
|
45
|
+
'--body', input.body,
|
|
46
|
+
...labelArgs,
|
|
47
|
+
], { encoding: 'utf-8', env, maxBuffer: 8 * 1024 * 1024 });
|
|
48
|
+
// `gh issue create` prints the new issue URL on stdout.
|
|
49
|
+
return { url: stdout.trim() };
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=proposal-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal-writer.js","sourceRoot":"","sources":["../../../src/cli/propose/proposal-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AA4BjD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAEhD,OAAO;QACL,KAAK,CAAC,mBAAmB,CAAC,KAAyB;YACjD,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACnC,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CACpC,IAAI,EACJ;gBACE,OAAO,EAAE,QAAQ;gBACjB,QAAQ,EAAE,KAAK,CAAC,IAAI;gBACpB,SAAS,EAAE,KAAK,CAAC,KAAK;gBACtB,QAAQ,EAAE,KAAK,CAAC,IAAI;gBACpB,GAAG,SAAS;aACb,EACD,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CACvD,CAAC;YACF,wDAAwD;YACxD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure formatters for the auditor Plan membrane (groundnuty/macf#503, DR-026 G1).
|
|
3
|
+
*
|
|
4
|
+
* Two outputs, both deterministic (no I/O, no clock):
|
|
5
|
+
* - `buildProposalBody` — the Markdown body of ONE ratifiable proposal issue,
|
|
6
|
+
* assembled from the AGENT-AUTHORED signal content (signal text + rationales)
|
|
7
|
+
* plus the mechanical metadata (tier, route, distinct-agent corroboration,
|
|
8
|
+
* invariant touchpoints, HIGH-RISK flag).
|
|
9
|
+
* - `buildReport` — the dry-run Markdown report printed to stdout/--output: the
|
|
10
|
+
* promoted candidates (each rendered as a proposal preview) PLUS a separate,
|
|
11
|
+
* visible "HELD (N<threshold)" section. The default mode opens NOTHING; this
|
|
12
|
+
* report IS the default-mode artifact.
|
|
13
|
+
*
|
|
14
|
+
* Every proposal makes its non-actuation explicit: the operator ratifies; the
|
|
15
|
+
* auditor never merges/applies (invariants #8 + #9).
|
|
16
|
+
*/
|
|
17
|
+
import { type ProposalIssueInput } from './proposal-writer.js';
|
|
18
|
+
import type { CandidateSet, ProposalCandidate } from './candidates.js';
|
|
19
|
+
/** A short, stable proposal title from the candidate. */
|
|
20
|
+
export declare function proposalTitle(c: ProposalCandidate): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the Markdown body for one ratifiable proposal issue. Pure assembly of
|
|
23
|
+
* agent-authored content + mechanical metadata; no LLM judgment is encoded.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildProposalBody(c: ProposalCandidate): string;
|
|
26
|
+
/** Build the full `ProposalIssueInput` (title + body + labels) for a candidate. */
|
|
27
|
+
export declare function buildProposalIssueInput(repo: string, c: ProposalCandidate): ProposalIssueInput;
|
|
28
|
+
export interface ReportInput {
|
|
29
|
+
readonly project: string;
|
|
30
|
+
readonly repo: string;
|
|
31
|
+
readonly candidates: CandidateSet;
|
|
32
|
+
/** True when `--file` was set (artifacts opened); false = dry-run report. */
|
|
33
|
+
readonly fileMode: boolean;
|
|
34
|
+
/** Whether `protected-invariants.md` was found + parsed (surfaced if not). */
|
|
35
|
+
readonly invariantsLoaded: boolean;
|
|
36
|
+
/** Count of reflection records read (for the summary line). */
|
|
37
|
+
readonly reflectionRecords: number;
|
|
38
|
+
/** Count of malformed reflection lines skipped (surfaced). */
|
|
39
|
+
readonly reflectionsSkipped: number;
|
|
40
|
+
/** Number of reflection ledger files read. */
|
|
41
|
+
readonly reflectionFiles: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the dry-run Markdown report. Promoted candidates render as previews; the
|
|
45
|
+
* HELD set renders in its own clearly-labelled section so a sub-threshold
|
|
46
|
+
* candidate is VISIBLE, never silently dropped.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildReport(input: ReportInput): string;
|
|
49
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/propose/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AActF,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAK1D;AAmCD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CA0D9D;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,iBAAiB,GACnB,kBAAkB,CAUpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,8DAA8D;IAC9D,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AA4BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAqFtD"}
|