@giamme/forge 0.0.0-stage → 0.9.0
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/CHANGELOG.md +205 -0
- package/LICENSE +21 -0
- package/README.md +194 -2
- package/SKILL.md +123 -0
- package/VERSION +1 -0
- package/docs/README.md +26 -0
- package/docs/add-ons.md +33 -0
- package/docs/artifacts.md +69 -0
- package/docs/commands.md +315 -0
- package/docs/dataset.md +20 -0
- package/docs/decomposed-runs.md +268 -0
- package/docs/development.md +95 -0
- package/docs/forge-ui.md +92 -0
- package/docs/fractal.md +181 -0
- package/docs/install.md +160 -0
- package/docs/memory.md +156 -0
- package/docs/models.md +118 -0
- package/docs/reviews.md +231 -0
- package/docs/safety.md +55 -0
- package/docs/troubleshooting.md +54 -0
- package/forge +79 -0
- package/package.json +27 -4
- package/references/dataset.md +329 -0
- package/references/decompose.md +667 -0
- package/references/fractal-dashboard.md +21 -0
- package/references/fractal.md +307 -0
- package/references/harnesses.md +365 -0
- package/references/jev.md +865 -0
- package/references/memory.md +228 -0
- package/references/planning.md +42 -0
- package/references/ripwire.md +47 -0
- package/references/runtime.md +64 -0
- package/references/solo.md +113 -0
- package/references/ui.md +112 -0
- package/registry.tsv +81 -0
- package/scripts/forge-artifact.sh +78 -0
- package/scripts/forge-contract.py +430 -0
- package/scripts/forge-dataset.py +6 -0
- package/scripts/forge-dispatch.sh +671 -0
- package/scripts/forge-fail-first.py +195 -0
- package/scripts/forge-fractal-dispatch.sh +4 -0
- package/scripts/forge-fractal-options.sh +54 -0
- package/scripts/forge-fractal.py +6 -0
- package/scripts/forge-guard.py +266 -0
- package/scripts/forge-install-fractal.sh +4 -0
- package/scripts/forge-install-ripwire.sh +52 -0
- package/scripts/forge-install.sh +135 -0
- package/scripts/forge-jev-options.sh +259 -0
- package/scripts/forge-jev.py +6 -0
- package/scripts/forge-lib-plans.sh +785 -0
- package/scripts/forge-lib-review.sh +494 -0
- package/scripts/forge-lib-task.sh +302 -0
- package/scripts/forge-lib-verify.sh +30 -0
- package/scripts/forge-memory.sh +575 -0
- package/scripts/forge-metrics.sh +39 -0
- package/scripts/forge-parallel-options.sh +76 -0
- package/scripts/forge-parallel.sh +1717 -0
- package/scripts/forge-plan-check.py +118 -0
- package/scripts/forge-prompt.py +45 -0
- package/scripts/forge-ripwire.py +136 -0
- package/scripts/forge-route.py +344 -0
- package/scripts/forge-runs.py +121 -0
- package/scripts/forge-runtime.py +586 -0
- package/scripts/forge-schedule.py +312 -0
- package/scripts/forge-shadow.py +305 -0
- package/scripts/forge-solo.sh +347 -0
- package/scripts/forge-ui-options.sh +42 -0
- package/scripts/forge-ui.py +435 -0
- package/scripts/forge-update.sh +71 -0
- package/scripts/forge-verify-coverage.py +956 -0
- package/scripts/forge-version.py +240 -0
- package/scripts/forge_dataset/__init__.py +439 -0
- package/scripts/forge_dataset/capture.py +330 -0
- package/scripts/forge_dataset/checks.py +109 -0
- package/scripts/forge_dataset/cli.py +233 -0
- package/scripts/forge_dataset/export.py +1009 -0
- package/scripts/forge_dataset/harvest.py +716 -0
- package/scripts/forge_dataset/importer.py +412 -0
- package/scripts/forge_dataset/outcomes.py +275 -0
- package/scripts/forge_dataset/routing.py +278 -0
- package/scripts/forge_fractal/__init__.py +84 -0
- package/scripts/forge_fractal/bridge.py +46 -0
- package/scripts/forge_fractal/cli.py +202 -0
- package/scripts/forge_fractal/dashboard.css +138 -0
- package/scripts/forge_fractal/dashboard.html +41 -0
- package/scripts/forge_fractal/dashboard.js +687 -0
- package/scripts/forge_fractal/decomposition.py +262 -0
- package/scripts/forge_fractal/execution.py +659 -0
- package/scripts/forge_fractal/inspection.py +261 -0
- package/scripts/forge_fractal/install.py +158 -0
- package/scripts/forge_fractal/invocation.py +94 -0
- package/scripts/forge_fractal/pipeline.py +124 -0
- package/scripts/forge_fractal/selection.py +179 -0
- package/scripts/forge_jev/__init__.py +376 -0
- package/scripts/forge_jev/backtest.py +322 -0
- package/scripts/forge_jev/cli.py +980 -0
- package/scripts/forge_jev/client.py +418 -0
- package/scripts/forge_jev/corpus.py +156 -0
- package/scripts/forge_jev/coupling.py +244 -0
- package/scripts/forge_jev/features.py +24 -0
- package/scripts/forge_jev/gates.py +100 -0
- package/scripts/forge_jev/memory.py +163 -0
- package/scripts/forge_jev/outcome.py +49 -0
- package/scripts/forge_jev/predict.py +204 -0
- package/scripts/forge_jev/questions.py +661 -0
- package/scripts/forge_jev/review.py +73 -0
- package/scripts/forge_jev/routing.py +271 -0
- package/scripts/forge_jev/subset.py +123 -0
- package/scripts/forge_jev/verify.py +453 -0
- package/scripts/forge_registry.py +140 -0
- package/ui/README.md +347 -0
- package/ui/THIRD_PARTY_NOTICES.md +177 -0
- package/ui/docs/api.md +970 -0
- package/ui/forge_ui/__init__.py +20 -0
- package/ui/forge_ui/__main__.py +135 -0
- package/ui/forge_ui/diffs.py +454 -0
- package/ui/forge_ui/executions.py +436 -0
- package/ui/forge_ui/export.py +214 -0
- package/ui/forge_ui/findings.py +132 -0
- package/ui/forge_ui/fractal.py +582 -0
- package/ui/forge_ui/models.py +216 -0
- package/ui/forge_ui/reader.py +1424 -0
- package/ui/forge_ui/server.py +312 -0
- package/ui/forge_ui/static/D-DINCondensed-Bold.woff2 +0 -0
- package/ui/forge_ui/static/app.js +1079 -0
- package/ui/forge_ui/static/cloud3d.js +647 -0
- package/ui/forge_ui/static/cloudmodel.js +375 -0
- package/ui/forge_ui/static/cloudui.js +397 -0
- package/ui/forge_ui/static/convo.js +295 -0
- package/ui/forge_ui/static/datatable.js +232 -0
- package/ui/forge_ui/static/diffview.js +235 -0
- package/ui/forge_ui/static/favicon.svg +1 -0
- package/ui/forge_ui/static/files.js +776 -0
- package/ui/forge_ui/static/findings3d.js +134 -0
- package/ui/forge_ui/static/gantt.js +97 -0
- package/ui/forge_ui/static/graph.js +266 -0
- package/ui/forge_ui/static/icons.js +94 -0
- package/ui/forge_ui/static/index.html +67 -0
- package/ui/forge_ui/static/iso.js +816 -0
- package/ui/forge_ui/static/leaderboard.js +311 -0
- package/ui/forge_ui/static/map3d.js +45 -0
- package/ui/forge_ui/static/modelstats.js +249 -0
- package/ui/forge_ui/static/notify.js +179 -0
- package/ui/forge_ui/static/panel.js +562 -0
- package/ui/forge_ui/static/runmodel.js +667 -0
- package/ui/forge_ui/static/scene3d.js +1471 -0
- package/ui/forge_ui/static/search.js +120 -0
- package/ui/forge_ui/static/shell.js +137 -0
- package/ui/forge_ui/static/stagectl.js +150 -0
- package/ui/forge_ui/static/style.css +1073 -0
- package/ui/forge_ui/static/theme.js +25 -0
- package/ui/forge_ui/transcripts.py +608 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""QA findings, parsed by forge's own contract module (scripts/forge-contract.py), never re-implemented."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import importlib.machinery
|
|
5
|
+
import importlib.util
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import re
|
|
8
|
+
import threading
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# build_id() hashes this package only, not forge-contract.py: a server keeps the parser it loaded
|
|
12
|
+
# first, and an edit to the contract is picked up by the next server, not by a running one.
|
|
13
|
+
CONTRACT = Path(__file__).resolve().parents[2] / 'scripts' / 'forge-contract.py'
|
|
14
|
+
_LOCK = threading.Lock()
|
|
15
|
+
_STATE = {}
|
|
16
|
+
# The contract reads whole replies; this only bounds a pathological file.
|
|
17
|
+
_MAX_CHARS = 1000000
|
|
18
|
+
_SUMMARY_MAX = 240
|
|
19
|
+
_TEXT_MAX = 20000
|
|
20
|
+
_GATE = ('threshold', 'decision', 'worst', 'n_confirmed', 'n_unlabelled', 'n_below')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _ReadOnlyLoader(importlib.machinery.SourceFileLoader):
|
|
24
|
+
def set_data(self, *args, **kwargs):
|
|
25
|
+
pass # forge-ui writes nothing, not even a .pyc beside forge's scripts
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _load():
|
|
29
|
+
with _LOCK:
|
|
30
|
+
if 'module' not in _STATE:
|
|
31
|
+
try:
|
|
32
|
+
spec = importlib.util.spec_from_file_location(
|
|
33
|
+
'forge_contract_for_ui', CONTRACT, loader=_ReadOnlyLoader('forge_contract_for_ui', str(CONTRACT)))
|
|
34
|
+
module = importlib.util.module_from_spec(spec)
|
|
35
|
+
spec.loader.exec_module(module)
|
|
36
|
+
if not (callable(module.parse_findings) and hasattr(module._LOCATION, 'search')):
|
|
37
|
+
raise TypeError('not the forge contract module')
|
|
38
|
+
_STATE['module'] = module
|
|
39
|
+
except Exception: # a missing or broken contract only turns findings off
|
|
40
|
+
_STATE['module'] = None
|
|
41
|
+
return _STATE['module']
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def available() -> bool:
|
|
45
|
+
return _load() is not None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# forge_verdict in scripts/forge-artifact.sh, as forge_dataset.harvest.verdict_of also ports it: only the
|
|
49
|
+
# reply's last non-blank line counts, and only as exactly `FORGE_VERDICT: PASS|FAIL`, optionally followed by
|
|
50
|
+
# a dash and a gloss. A verdict anywhere else (quoted, followed by more text) is no verdict, as for forge.
|
|
51
|
+
_VERDICT = re.compile(r'^FORGE_VERDICT: (PASS|FAIL)([ \t]+(—|–|-)( .*)?)?[ \t]*$')
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def verdict(text):
|
|
55
|
+
"""PASS, FAIL or None, exactly as forge decides it: from the reply's last non-blank line only.
|
|
56
|
+
|
|
57
|
+
None means forge recorded no verdict (UNKNOWN), which forge's gate treats as blocking."""
|
|
58
|
+
lines = [line for line in (text or '').splitlines() if line.strip()]
|
|
59
|
+
match = _VERDICT.match(lines[-1].rstrip('\r')) if lines else None
|
|
60
|
+
return match.group(1) if match else None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _parse(text):
|
|
64
|
+
module = _load()
|
|
65
|
+
if module is None or not text:
|
|
66
|
+
return None, None
|
|
67
|
+
try:
|
|
68
|
+
found = []
|
|
69
|
+
for item in module.parse_findings(text[:_MAX_CHARS]):
|
|
70
|
+
severity = item.severity if type(item.severity) is int and 0 <= item.severity <= 3 else None
|
|
71
|
+
if item.status in ('CONFIRMED', 'PLAUSIBLE', 'UNSTATED') and isinstance(item.text, str):
|
|
72
|
+
found.append((item.status, severity, item.line if type(item.line) is int else None, item.text))
|
|
73
|
+
return module, found
|
|
74
|
+
except Exception:
|
|
75
|
+
return None, None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def summarize(text):
|
|
79
|
+
"""FindingsSummary of a reply, or None when there is no text or no contract module."""
|
|
80
|
+
found = _parse(text)[1]
|
|
81
|
+
if found is None:
|
|
82
|
+
return None
|
|
83
|
+
result = dict(P0=0, P1=0, P2=0, P3=0, unlabelled=0, plausible=0, confirmed=0, worst=None)
|
|
84
|
+
for status, severity, _, _ in found:
|
|
85
|
+
if status == 'CONFIRMED':
|
|
86
|
+
result['confirmed'] += 1
|
|
87
|
+
if severity is None:
|
|
88
|
+
result['unlabelled'] += 1
|
|
89
|
+
else:
|
|
90
|
+
result['P%d' % severity] += 1
|
|
91
|
+
elif status == 'PLAUSIBLE':
|
|
92
|
+
result['plausible'] += 1
|
|
93
|
+
else:
|
|
94
|
+
result['unlabelled'] += 1 # UNSTATED counts as unlabelled, as in the gate
|
|
95
|
+
labelled = [severity for status, severity, _, _ in found if status == 'CONFIRMED' and severity is not None]
|
|
96
|
+
result['worst'] = 'P%d' % min(labelled) if labelled else None
|
|
97
|
+
return result
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def listing(text, limit=200):
|
|
101
|
+
"""The first `limit` Findings of a reply, or None when there is no text or no contract module."""
|
|
102
|
+
module, found = _parse(text)
|
|
103
|
+
if found is None:
|
|
104
|
+
return None
|
|
105
|
+
result = []
|
|
106
|
+
for status, severity, line, block in found[:limit]:
|
|
107
|
+
first = block.split('\n', 1)[0]
|
|
108
|
+
try:
|
|
109
|
+
match = module._LOCATION.search(first)
|
|
110
|
+
except Exception:
|
|
111
|
+
match = None
|
|
112
|
+
result.append(dict(severity=None if severity is None else 'P%d' % severity, status=status,
|
|
113
|
+
location=match.group(0) if match else None, line=line,
|
|
114
|
+
summary=first.strip()[:_SUMMARY_MAX],
|
|
115
|
+
text=block if len(block) <= _TEXT_MAX else block[:_TEXT_MAX] + '…'))
|
|
116
|
+
return result
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def parse_gate(text):
|
|
120
|
+
"""A qa.gate line: threshold, decision, worst, n_confirmed, n_unlabelled, n_below; None if malformed."""
|
|
121
|
+
line = next((item for item in (text or '').splitlines() if item.strip()), None)
|
|
122
|
+
parts = line.rstrip('\r').split('\t') if line else []
|
|
123
|
+
if len(parts) < len(_GATE):
|
|
124
|
+
return None
|
|
125
|
+
result = {}
|
|
126
|
+
for key, value in zip(_GATE, parts):
|
|
127
|
+
value = value.strip()
|
|
128
|
+
if key.startswith('n_'):
|
|
129
|
+
result[key] = int(value) if re.fullmatch(r'[0-9]{1,9}', value) else None
|
|
130
|
+
else:
|
|
131
|
+
result[key] = None if value in ('', '-') else value
|
|
132
|
+
return result
|