@foggy-projects/deepseek-harness-plugin 0.4.0-beta.5 → 0.4.0-beta.6
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/README.md +9 -3
- package/lib/client.js +3 -0
- package/lib/index.js +6 -3
- package/package.json +2 -2
- package/skills/foggy-deepseek-onboarding/SKILL.md +18 -2
- package/skills/foggy-deepseek-onboarding/assets/versions.json +1 -1
- package/skills/foggy-deepseek-onboarding/references/onboarding-workflow.md +22 -0
- package/skills/foggy-deepseek-onboarding/scripts/onboarding.py +360 -133
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ only when the user selects **Initialize Foggy**.
|
|
|
8
8
|
## Local beta installation
|
|
9
9
|
|
|
10
10
|
```powershell
|
|
11
|
-
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.0-beta.
|
|
11
|
+
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.0-beta.6.tgz
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
Restart `dsh web`, open Settings → Plugins → Foggy Data Analysis, and initialize
|
|
@@ -23,8 +23,9 @@ dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-p
|
|
|
23
23
|
For development, `FOGGY_ASSET_CACHE_DIRS` can contain platform-delimited verified
|
|
24
24
|
asset-cache directories. It is not required for a normal install.
|
|
25
25
|
|
|
26
|
-
Database credentials
|
|
27
|
-
|
|
26
|
+
Database credentials remain outside the ordinary DSH settings document. The
|
|
27
|
+
bundled onboarding Skill drives datasource discovery, semantic drafting,
|
|
28
|
+
checkpointed publication, and bounded read-only query verification.
|
|
28
29
|
|
|
29
30
|
## Native Skill and workspace contract
|
|
30
31
|
|
|
@@ -34,6 +35,11 @@ are available in every DSH workspace without copying or symlinking `.agents`.
|
|
|
34
35
|
The current session `cwd` remains the workspace boundary for semantic drafts and
|
|
35
36
|
evidence.
|
|
36
37
|
|
|
38
|
+
Opaque CLI profiles default to the private persistent
|
|
39
|
+
`<dataRoot>/cli-profiles` directory. Composite onboarding commands are
|
|
40
|
+
idempotent: unchanged completed phases are resumed rather than re-adding a
|
|
41
|
+
datasource or re-registering a published bundle.
|
|
42
|
+
|
|
37
43
|
CLI, Launcher, the analysis Skill, install state, and Runtime state live in the
|
|
38
44
|
user-level Foggy component directories. The managed CLI is intentionally isolated
|
|
39
45
|
and does not need to be on `PATH`. **Re-download / Repair** verifies the global
|
package/lib/client.js
CHANGED
|
@@ -68,6 +68,7 @@ window.__ModuleLoader__.load({
|
|
|
68
68
|
roots: '本地目录',
|
|
69
69
|
installRoot: '组件目录',
|
|
70
70
|
dataRoot: '数据目录',
|
|
71
|
+
profileStore: 'CLI Profile',
|
|
71
72
|
runtimeUrl: 'Runtime 地址',
|
|
72
73
|
nextTitle: '后续配置',
|
|
73
74
|
nextCopy: 'Skills 已通过 DeepSeek Harness 原生注册表提供给所有工作区;每个会话直接使用自己的工作目录。Runtime 启动成功后,将继续进入数据库连接与语义层向导。',
|
|
@@ -116,6 +117,7 @@ window.__ModuleLoader__.load({
|
|
|
116
117
|
roots: 'Local directories',
|
|
117
118
|
installRoot: 'Components',
|
|
118
119
|
dataRoot: 'Data',
|
|
120
|
+
profileStore: 'CLI profiles',
|
|
119
121
|
runtimeUrl: 'Runtime URL',
|
|
120
122
|
nextTitle: 'Next configuration',
|
|
121
123
|
nextCopy: 'Skills are provided to every workspace through the native DeepSeek Harness registry, and each session uses its own working directory. After Runtime starts, the database connection and semantic-layer wizard comes next.',
|
|
@@ -288,6 +290,7 @@ window.__ModuleLoader__.load({
|
|
|
288
290
|
jsxs('dl', { children: [
|
|
289
291
|
jsx('dt', { children: t('installRoot') }), jsx('dd', { children: status.roots.installRoot }),
|
|
290
292
|
jsx('dt', { children: t('dataRoot') }), jsx('dd', { children: status.roots.dataRoot }),
|
|
293
|
+
jsx('dt', { children: t('profileStore') }), jsx('dd', { children: status.roots.profileStore }),
|
|
291
294
|
status.runtimeUrl ? jsx('dt', { children: t('runtimeUrl') }) : null,
|
|
292
295
|
status.runtimeUrl ? jsx('dd', { children: status.runtimeUrl }) : null,
|
|
293
296
|
] }),
|
package/lib/index.js
CHANGED
|
@@ -20,17 +20,20 @@ function defaultRoots() {
|
|
|
20
20
|
return {
|
|
21
21
|
installRoot: join(base, 'Foggy', 'DeepSeekHarness'),
|
|
22
22
|
dataRoot: join(base, 'Foggy', 'DeepSeekHarnessData'),
|
|
23
|
+
profileStore: process.env.FOGGY_RUNTIME_PROFILE_STORE || join(base, 'Foggy', 'DeepSeekHarnessData', 'cli-profiles'),
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
const home = process.env.HOME
|
|
26
27
|
if (!home) throw new Error('HOME is not set')
|
|
28
|
+
const dataRoot = process.env.XDG_STATE_HOME
|
|
29
|
+
? join(process.env.XDG_STATE_HOME, 'foggy', 'deepseek-harness')
|
|
30
|
+
: join(home, '.local', 'state', 'foggy', 'deepseek-harness')
|
|
27
31
|
return {
|
|
28
32
|
installRoot: process.env.XDG_DATA_HOME
|
|
29
33
|
? join(process.env.XDG_DATA_HOME, 'foggy', 'deepseek-harness')
|
|
30
34
|
: join(home, '.local', 'share', 'foggy', 'deepseek-harness'),
|
|
31
|
-
dataRoot
|
|
32
|
-
|
|
33
|
-
: join(home, '.local', 'state', 'foggy', 'deepseek-harness'),
|
|
35
|
+
dataRoot,
|
|
36
|
+
profileStore: process.env.FOGGY_RUNTIME_PROFILE_STORE || join(dataRoot, 'cli-profiles'),
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foggy-projects/deepseek-harness-plugin",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.6",
|
|
4
4
|
"description": "Foggy Java data analysis engine integration for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -55,6 +55,6 @@
|
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"check": "node --check lib/index.js && node --check lib/skill-provider.js && node --check lib/client.js && node --check lib/typert.js && node --check lib/remote.js",
|
|
58
|
-
"test": "node --test test/package.test.js"
|
|
58
|
+
"test": "node --test test/package.test.js && python test/onboarding_unit.py"
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -24,6 +24,12 @@ copy this Skill into the current workspace.
|
|
|
24
24
|
analysis Skill is missing or invalid, ask the user to open the Foggy plugin settings and use
|
|
25
25
|
**Re-download / Repair**. Repair restores the global managed analysis Skill and invalidates the
|
|
26
26
|
native DSH Skill catalog. Reinstall or upgrade the plugin itself to restore this bundled Skill.
|
|
27
|
+
- Treat the current DSH session workspace as the authoritative `projectRoot` for the whole onboarding
|
|
28
|
+
run. Do not redirect semantic drafts or contracts to a different repository merely because another
|
|
29
|
+
Skill or example was found there. Place non-secret contracts below
|
|
30
|
+
`<projectRoot>/.foggy/onboarding-contracts/<profile>/`, drafts below
|
|
31
|
+
`<projectRoot>/.foggy/onboarding-drafts/<profile>/`, and published files below the approved
|
|
32
|
+
project-relative `modelsDir`.
|
|
27
33
|
|
|
28
34
|
## Mandatory orchestration boundary
|
|
29
35
|
|
|
@@ -46,6 +52,9 @@ For every new-database onboarding session, this Skill is the orchestration autho
|
|
|
46
52
|
- Never read query-execution evidence back into the conversation. Report only validation state,
|
|
47
53
|
execution state, row count, and evidence path; do not report row values or generated SQL containing
|
|
48
54
|
business literals.
|
|
55
|
+
- Prefer one composite command per approval boundary. Do not inspect this Skill's Python implementation
|
|
56
|
+
or the CLI package source during a normal run; use the documented command contract and inspect code
|
|
57
|
+
only after a structured wrapper error requires troubleshooting.
|
|
49
58
|
|
|
50
59
|
## Boundaries
|
|
51
60
|
|
|
@@ -70,10 +79,12 @@ For every new-database onboarding session, this Skill is the orchestration autho
|
|
|
70
79
|
4. Load `foggy-ai-analysis` from the native DSH Skill registry. Do not require a workspace copy.
|
|
71
80
|
5. For a new business database, read [references/onboarding-workflow.md](references/onboarding-workflow.md)
|
|
72
81
|
and prefer its two composite `onboard-datasource-run` / `onboard-semantic-run` commands. Require the
|
|
73
|
-
trusted operator to create the private CLI profile outside Harness.
|
|
82
|
+
trusted operator to create the private CLI profile outside Harness. Unless the operator explicitly
|
|
83
|
+
overrides it, use the persistent profile store reported by the wrapper under the Foggy data root
|
|
84
|
+
(`<dataRoot>/cli-profiles`), never `/tmp`. Accept only the opaque profile
|
|
74
85
|
ID, exact revision, datasource name/type, and namespace; never request JDBC URL, username,
|
|
75
86
|
password, or password environment-variable name in Harness.
|
|
76
|
-
6. After schema discovery, use `foggy-ai-analysis` only to author TM/QM files in
|
|
87
|
+
6. After schema discovery, use `foggy-ai-analysis` only to author TM/QM files in the standard project-local
|
|
77
88
|
draft directory. Register, validate, publish, and verify them through this Skill's wrapper using the deterministic commands in
|
|
78
89
|
[references/onboarding-workflow.md](references/onboarding-workflow.md). Do not publish, prune, replace
|
|
79
90
|
a bundle, or execute a business-data query without the matching explicit flag and user approval.
|
|
@@ -98,5 +109,10 @@ In DeepSeek Harness, do not expand the composite onboarding commands back into t
|
|
|
98
109
|
operations. This order documents what the wrapper enforces internally and becomes a direct CLI workflow
|
|
99
110
|
only after onboarding is complete.
|
|
100
111
|
|
|
112
|
+
Composite commands are checkpointed and idempotent: a retry skips completed datasource, validation,
|
|
113
|
+
publication, and verification phases when the approved contract and draft digest are unchanged. Fix a
|
|
114
|
+
query payload in place and rerun the same semantic composite command; do not remove a successfully
|
|
115
|
+
published bundle merely to recover from a later query-validation failure.
|
|
116
|
+
|
|
101
117
|
Keep user business data separate from the sales-drop SQLite demo. Prefer a read-only database account,
|
|
102
118
|
opaque CLI profile references, and bounded query limits.
|
|
@@ -23,6 +23,16 @@ to paste a password and do not put a JDBC URL, username, password environment-va
|
|
|
23
23
|
line, logs, or evidence. For non-SQLite databases, ask the user to set the named environment variable
|
|
24
24
|
before Runtime starts so the Java process inherits it. Recommend a read-only database account.
|
|
25
25
|
|
|
26
|
+
Use the current DSH session workspace as `projectRoot`. Store approved non-secret contracts at
|
|
27
|
+
`.foggy/onboarding-contracts/<profile>/`, semantic drafts at `.foggy/onboarding-drafts/<profile>/`, and
|
|
28
|
+
command evidence at `.foggy/onboarding-command-evidence/<profile>/`. Do not split these files across the
|
|
29
|
+
session workspace and a separate example repository. The wrapper rejects a query payload outside the
|
|
30
|
+
recorded project root before any semantic validation or publication mutation occurs.
|
|
31
|
+
|
|
32
|
+
The wrapper defaults `FOGGY_RUNTIME_PROFILE_STORE` to the private persistent directory
|
|
33
|
+
`<dataRoot>/cli-profiles`. An explicit operator-provided value still wins. Do not use `/tmp` for a profile
|
|
34
|
+
that must survive a WSL or Harness restart.
|
|
35
|
+
|
|
26
36
|
Treat every user-supplied identifier and bound as immutable input: profile, datasource, namespace,
|
|
27
37
|
models directory, bundle name, TM/QM name, query fields, and limit. Do not swap in demo names, add
|
|
28
38
|
fields, raise the limit, or introduce replacement flags. If one of these inputs is missing, pause for
|
|
@@ -53,6 +63,13 @@ onboard-semantic-run --semantic-plan <approved-json> --query-payload <approved-j
|
|
|
53
63
|
Include an approval flag only after the user approves that exact action. Without it, the composite
|
|
54
64
|
command stops after the corresponding dry-run and returns `phaseStatus=awaiting-...-approval`.
|
|
55
65
|
|
|
66
|
+
Both composite commands are resumable. When the approved contract is unchanged, they skip completed
|
|
67
|
+
checkpoints instead of re-adding an existing datasource, revalidating an already published draft, or
|
|
68
|
+
registering the same bundle twice. If query validation fails after publication, correct the project-local
|
|
69
|
+
payload and rerun `onboard-semantic-run`; it resumes at query verification and leaves the active bundle in
|
|
70
|
+
place. A same-name datasource is accepted idempotently only when its public name and database type match
|
|
71
|
+
the approved plan; otherwise replacement still requires explicit approval.
|
|
72
|
+
|
|
56
73
|
The granular commands below remain available for manual troubleshooting and resumption. Do not expand
|
|
57
74
|
the composite commands into this list during a normal Harness turn.
|
|
58
75
|
|
|
@@ -111,6 +128,11 @@ requires an integer `limit` from 1 through 100. The first `semantic-verify` call
|
|
|
111
128
|
validates the query; only `--execute` reads business data. Full results stay in evidence and the command
|
|
112
129
|
returns only counts and paths.
|
|
113
130
|
|
|
131
|
+
Before the first semantic mutation, the composite command checks that the query payload is inside
|
|
132
|
+
`projectRoot`, has a bounded limit, and targets a query model declared in the approved semantic plan.
|
|
133
|
+
After publication, `semantic-verify` always describes the live model before validation. If a field is
|
|
134
|
+
rejected, update the payload from those described names and rerun the same composite command.
|
|
135
|
+
|
|
114
136
|
Do not open, summarize, or quote `query-execute.json` or the Runtime's generated SQL after execution.
|
|
115
137
|
The conversational result may contain only `queryValidated`, `queryExecuted`, `rowCount`, the model
|
|
116
138
|
name, and the evidence path. A successful direct CLI command is not proof that onboarding completed;
|
|
@@ -448,6 +448,33 @@ def onboarding_state_path(data_root: Path, profile: str) -> Path:
|
|
|
448
448
|
return data_root / "onboarding" / "profiles" / f"{safe_profile(profile)}.json"
|
|
449
449
|
|
|
450
450
|
|
|
451
|
+
def configure_profile_store(data_root: Path, *, create: bool = True) -> Path:
|
|
452
|
+
"""Keep opaque CLI profiles in the persistent, private Foggy data root by default."""
|
|
453
|
+
configured = os.environ.get("FOGGY_RUNTIME_PROFILE_STORE")
|
|
454
|
+
destination = normalized(configured) if configured else data_root / "cli-profiles"
|
|
455
|
+
if not configured:
|
|
456
|
+
os.environ["FOGGY_RUNTIME_PROFILE_STORE"] = str(destination)
|
|
457
|
+
if create:
|
|
458
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
459
|
+
if os.name != "nt":
|
|
460
|
+
destination.chmod(0o700)
|
|
461
|
+
return destination
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def resolve_profile_name(data_root: Path, requested: str | None) -> str:
|
|
465
|
+
if requested:
|
|
466
|
+
return safe_profile(requested)
|
|
467
|
+
profiles_dir = data_root / "onboarding" / "profiles"
|
|
468
|
+
candidates = sorted(path.stem for path in profiles_dir.glob("*.json") if PROFILE_PATTERN.fullmatch(path.stem))
|
|
469
|
+
if len(candidates) == 1:
|
|
470
|
+
return candidates[0]
|
|
471
|
+
if not candidates:
|
|
472
|
+
return "default"
|
|
473
|
+
raise OnboardingError(
|
|
474
|
+
"Multiple onboarding profiles exist; pass --profile explicitly: " + ", ".join(candidates)
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
|
|
451
478
|
def read_onboarding_state(data_root: Path, profile: str, required: bool = True) -> dict | None:
|
|
452
479
|
path = onboarding_state_path(data_root, profile)
|
|
453
480
|
if not path.is_file():
|
|
@@ -802,10 +829,12 @@ def install_command(args: argparse.Namespace) -> dict:
|
|
|
802
829
|
assert_managed_root(data_root, "Data root")
|
|
803
830
|
if install_root == data_root:
|
|
804
831
|
raise OnboardingError("Install root and data root must be different")
|
|
832
|
+
profile_store = normalized(os.environ.get("FOGGY_RUNTIME_PROFILE_STORE") or data_root / "cli-profiles")
|
|
805
833
|
plan = {
|
|
806
834
|
"schemaVersion": "foggy-deepseek-onboarding-plan/v1",
|
|
807
835
|
"installRoot": str(install_root),
|
|
808
836
|
"dataRoot": str(data_root),
|
|
837
|
+
"profileStore": str(profile_store),
|
|
809
838
|
"workspaceMode": "dsh-session-cwd",
|
|
810
839
|
"versions": {name: value.get("version") for name, value in components.items()},
|
|
811
840
|
"operations": ["install isolated CLI", "verify Launcher assets", "install global analysis Skill", "write install state"],
|
|
@@ -813,6 +842,7 @@ def install_command(args: argparse.Namespace) -> dict:
|
|
|
813
842
|
}
|
|
814
843
|
if args.dry_run:
|
|
815
844
|
return {"success": True, "dryRun": True, "plan": plan}
|
|
845
|
+
profile_store = configure_profile_store(data_root)
|
|
816
846
|
progress = ProgressReporter(
|
|
817
847
|
getattr(args, "progress_file", None),
|
|
818
848
|
getattr(args, "operation_id", None),
|
|
@@ -945,6 +975,7 @@ def install_command(args: argparse.Namespace) -> dict:
|
|
|
945
975
|
"packageVersion": versions["packageVersion"],
|
|
946
976
|
"installRoot": str(install_root),
|
|
947
977
|
"dataRoot": str(data_root),
|
|
978
|
+
"profileStore": str(profile_store),
|
|
948
979
|
"workspaceMode": "dsh-session-cwd",
|
|
949
980
|
"cli": {"version": cli_component["version"], "command": str(cli_command), "mode": cli_mode},
|
|
950
981
|
"launcher": {"version": components["launcher"]["version"], "path": str(launcher_dir)},
|
|
@@ -1163,6 +1194,7 @@ def onboarding_context(args: argparse.Namespace, require_runtime: bool = False)
|
|
|
1163
1194
|
install_state = read_install_state(install_root)
|
|
1164
1195
|
data_root = normalized(args.data_root or install_state["dataRoot"])
|
|
1165
1196
|
assert_managed_root(data_root, "Data root")
|
|
1197
|
+
configure_profile_store(data_root, create=False)
|
|
1166
1198
|
runtime_state_path = data_root / "runtime-state.json"
|
|
1167
1199
|
runtime_state = read_json_object(runtime_state_path, "Runtime state") if runtime_state_path.is_file() else None
|
|
1168
1200
|
if runtime_state and runtime_state.get("schemaVersion") != RUNTIME_STATE_SCHEMA:
|
|
@@ -1222,6 +1254,28 @@ def require_opaque_profile_cli(install_state: dict) -> None:
|
|
|
1222
1254
|
)
|
|
1223
1255
|
|
|
1224
1256
|
|
|
1257
|
+
def datasource_entries(payload: dict) -> list[dict]:
|
|
1258
|
+
for item in nested_data_objects(payload):
|
|
1259
|
+
entries = item.get("datasources")
|
|
1260
|
+
if isinstance(entries, list):
|
|
1261
|
+
return [entry for entry in entries if isinstance(entry, dict)]
|
|
1262
|
+
return []
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
def matching_datasource(payload: dict, connection: dict) -> dict | None:
|
|
1266
|
+
expected_name = connection["name"]
|
|
1267
|
+
expected_type = connection["type"].lower()
|
|
1268
|
+
if expected_type == "postgresql":
|
|
1269
|
+
expected_type = "postgres"
|
|
1270
|
+
for entry in datasource_entries(payload):
|
|
1271
|
+
entry_type = str(entry.get("type", "")).lower()
|
|
1272
|
+
if entry_type == "postgresql":
|
|
1273
|
+
entry_type = "postgres"
|
|
1274
|
+
if entry.get("name") == expected_name and entry_type == expected_type:
|
|
1275
|
+
return entry
|
|
1276
|
+
return None
|
|
1277
|
+
|
|
1278
|
+
|
|
1225
1279
|
def onboarding_plan_command(args: argparse.Namespace) -> dict:
|
|
1226
1280
|
install_root, install_state, data_root, runtime_state = onboarding_context(args, require_runtime=False)
|
|
1227
1281
|
profile = safe_profile(args.profile)
|
|
@@ -1283,7 +1337,9 @@ def onboarding_plan_command(args: argparse.Namespace) -> dict:
|
|
|
1283
1337
|
|
|
1284
1338
|
def require_profile(args: argparse.Namespace, require_runtime: bool = False) -> tuple[dict, dict, Path, dict | None]:
|
|
1285
1339
|
_install_root, install_state, data_root, runtime_state = onboarding_context(args, require_runtime=require_runtime)
|
|
1286
|
-
|
|
1340
|
+
profile = resolve_profile_name(data_root, getattr(args, "profile", None))
|
|
1341
|
+
args.profile = profile
|
|
1342
|
+
state = read_onboarding_state(data_root, profile)
|
|
1287
1343
|
if normalized(state["installRoot"]) != normalized(install_state["installRoot"]):
|
|
1288
1344
|
raise OnboardingError("Onboarding profile belongs to a different install root")
|
|
1289
1345
|
return state, install_state, data_root, runtime_state
|
|
@@ -1329,10 +1385,31 @@ def datasource_configure_command(args: argparse.Namespace) -> dict:
|
|
|
1329
1385
|
label = "datasources add"
|
|
1330
1386
|
if args.replace:
|
|
1331
1387
|
command.append("--replace")
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1388
|
+
already_present = False
|
|
1389
|
+
try:
|
|
1390
|
+
result = redact_connection_material(
|
|
1391
|
+
cli_json(install_state, runtime_state, connection["namespace"], command, label)
|
|
1392
|
+
)
|
|
1393
|
+
except OnboardingError as exc:
|
|
1394
|
+
if "DATASOURCE_ALREADY_EXISTS" not in str(exc):
|
|
1395
|
+
raise
|
|
1396
|
+
listed = cli_json(
|
|
1397
|
+
install_state, runtime_state, connection["namespace"], ["datasources", "list"], "datasources list"
|
|
1398
|
+
)
|
|
1399
|
+
existing = matching_datasource(listed, connection)
|
|
1400
|
+
if existing is None:
|
|
1401
|
+
raise OnboardingError(
|
|
1402
|
+
f"Datasource {connection['name']} already exists but its public type does not match the approved plan; "
|
|
1403
|
+
"do not replace it without explicit approval"
|
|
1404
|
+
) from exc
|
|
1405
|
+
already_present = True
|
|
1406
|
+
result = {
|
|
1407
|
+
"success": True,
|
|
1408
|
+
"idempotent": True,
|
|
1409
|
+
"status": "already-present",
|
|
1410
|
+
"dataSource": redact_connection_material(existing),
|
|
1411
|
+
}
|
|
1412
|
+
mark_step(state, "datasourceConfigured", "completed", replace=args.replace, alreadyPresent=already_present)
|
|
1336
1413
|
path = write_onboarding_state(data_root, state)
|
|
1337
1414
|
return {
|
|
1338
1415
|
"success": True,
|
|
@@ -1340,6 +1417,7 @@ def datasource_configure_command(args: argparse.Namespace) -> dict:
|
|
|
1340
1417
|
"profile": state["profile"],
|
|
1341
1418
|
"statePath": str(path),
|
|
1342
1419
|
"dataSource": connection["name"],
|
|
1420
|
+
"alreadyPresent": already_present,
|
|
1343
1421
|
"runtime": result,
|
|
1344
1422
|
"next": "run datasource-verify; add --bind to approve namespace binding",
|
|
1345
1423
|
"productionReady": False,
|
|
@@ -1798,7 +1876,16 @@ def semantic_verify_command(args: argparse.Namespace) -> dict:
|
|
|
1798
1876
|
)
|
|
1799
1877
|
atomic_json(evidence_dir / "query-execute.json", executed)
|
|
1800
1878
|
row_count = response_row_count(executed)
|
|
1801
|
-
mark_step(
|
|
1879
|
+
mark_step(
|
|
1880
|
+
state,
|
|
1881
|
+
"semanticVerified",
|
|
1882
|
+
"completed",
|
|
1883
|
+
queryModel=query_model,
|
|
1884
|
+
queryValidated=True,
|
|
1885
|
+
queryExecuted=True,
|
|
1886
|
+
rowCount=row_count,
|
|
1887
|
+
queryPayloadDigest=sha256(payload_path),
|
|
1888
|
+
)
|
|
1802
1889
|
state.setdefault("artifacts", {})["semanticVerifyEvidence"] = str(evidence_dir)
|
|
1803
1890
|
path = write_onboarding_state(data_root, state)
|
|
1804
1891
|
return {
|
|
@@ -1818,14 +1905,15 @@ def semantic_verify_command(args: argparse.Namespace) -> dict:
|
|
|
1818
1905
|
|
|
1819
1906
|
|
|
1820
1907
|
def next_onboarding_action(state: dict) -> dict:
|
|
1908
|
+
profile_flag = f" --profile {state['profile']}"
|
|
1821
1909
|
ordered = [
|
|
1822
|
-
("datasourceConfigured", "datasource-configure --apply"),
|
|
1823
|
-
("datasourceVerified", "datasource-verify --bind"),
|
|
1824
|
-
("schemaDiscovered", "schema-discover"),
|
|
1825
|
-
("semanticDrafted", "semantic-draft --semantic-plan <json>"),
|
|
1826
|
-
("semanticValidated", "semantic-validate --apply"),
|
|
1827
|
-
("semanticPublished", "semantic-publish --apply"),
|
|
1828
|
-
("semanticVerified", "semantic-verify --query-payload <json> --execute"),
|
|
1910
|
+
("datasourceConfigured", f"datasource-configure{profile_flag} --apply"),
|
|
1911
|
+
("datasourceVerified", f"datasource-verify{profile_flag} --bind"),
|
|
1912
|
+
("schemaDiscovered", f"schema-discover{profile_flag}"),
|
|
1913
|
+
("semanticDrafted", f"semantic-draft{profile_flag} --semantic-plan <json>"),
|
|
1914
|
+
("semanticValidated", f"semantic-validate{profile_flag} --apply"),
|
|
1915
|
+
("semanticPublished", f"semantic-publish{profile_flag} --apply"),
|
|
1916
|
+
("semanticVerified", f"semantic-verify{profile_flag} --query-payload <json> --execute"),
|
|
1829
1917
|
]
|
|
1830
1918
|
for name, command in ordered:
|
|
1831
1919
|
current = state.get("steps", {}).get(name, {})
|
|
@@ -1838,7 +1926,7 @@ def next_onboarding_action(state: dict) -> dict:
|
|
|
1838
1926
|
"instruction": "Inspect semantic publish evidence and repair refresh before any republish attempt.",
|
|
1839
1927
|
}
|
|
1840
1928
|
if name == "semanticValidated" and current.get("status") == "failed":
|
|
1841
|
-
command = "repair TM/QM, then semantic-draft --semantic-plan <json>"
|
|
1929
|
+
command = f"repair TM/QM, then semantic-draft{profile_flag} --semantic-plan <json>"
|
|
1842
1930
|
return {"step": name, "command": command, "status": current.get("status", "pending")}
|
|
1843
1931
|
return {"step": None, "command": None, "status": "completed"}
|
|
1844
1932
|
|
|
@@ -1883,6 +1971,21 @@ def save_composite_result(evidence_dir: Path, name: str, payload: dict, files: l
|
|
|
1883
1971
|
files.append(str(path))
|
|
1884
1972
|
|
|
1885
1973
|
|
|
1974
|
+
def resumed_phase(profile: str, phase: str, **values: object) -> dict:
|
|
1975
|
+
return {
|
|
1976
|
+
"success": True,
|
|
1977
|
+
"schemaVersion": "foggy-deepseek-onboarding-resumed/v1",
|
|
1978
|
+
"profile": profile,
|
|
1979
|
+
"phase": phase,
|
|
1980
|
+
"resumed": True,
|
|
1981
|
+
**values,
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
|
|
1985
|
+
def step_completed(state: dict, name: str) -> bool:
|
|
1986
|
+
return state.get("steps", {}).get(name, {}).get("status") == "completed"
|
|
1987
|
+
|
|
1988
|
+
|
|
1886
1989
|
def datasource_run_command(args: argparse.Namespace) -> dict:
|
|
1887
1990
|
_install_root, install_state, data_root, _runtime_state = onboarding_context(args, require_runtime=True)
|
|
1888
1991
|
project_root = normalized(args.project_root or Path.cwd())
|
|
@@ -1902,6 +2005,11 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
|
|
|
1902
2005
|
if existing:
|
|
1903
2006
|
if existing.get("connection") != requested_connection:
|
|
1904
2007
|
raise OnboardingError("Existing onboarding profile does not match the requested connection plan")
|
|
2008
|
+
if normalized(existing.get("projectRoot", "")) != project_root:
|
|
2009
|
+
raise OnboardingError(
|
|
2010
|
+
"Existing onboarding profile belongs to a different projectRoot; resume from that DSH workspace "
|
|
2011
|
+
"or choose a new profile name"
|
|
2012
|
+
)
|
|
1905
2013
|
plan_result = {
|
|
1906
2014
|
"success": True,
|
|
1907
2015
|
"schemaVersion": "foggy-deepseek-onboarding-plan-result/v1",
|
|
@@ -1921,59 +2029,81 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
|
|
|
1921
2029
|
replace_plan=False,
|
|
1922
2030
|
))
|
|
1923
2031
|
save_composite_result(evidence_dir, "01-plan.json", plan_result, files)
|
|
2032
|
+
state = read_onboarding_state(data_root, profile)
|
|
1924
2033
|
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
return {
|
|
1951
|
-
"success": True,
|
|
1952
|
-
"schemaVersion": "foggy-deepseek-datasource-run/v1",
|
|
1953
|
-
"profile": profile,
|
|
1954
|
-
"phaseStatus": "awaiting-bind-approval",
|
|
1955
|
-
"evidenceDir": str(evidence_dir),
|
|
1956
|
-
"evidenceFiles": files,
|
|
1957
|
-
"next": "rerun with --approve-configure --approve-bind after namespace binding is approved",
|
|
1958
|
-
"productionReady": False,
|
|
1959
|
-
}
|
|
2034
|
+
if step_completed(state, "datasourceConfigured"):
|
|
2035
|
+
configured = resumed_phase(profile, "datasourceConfigured")
|
|
2036
|
+
save_composite_result(evidence_dir, "02-datasource-dry.json", configured, files)
|
|
2037
|
+
save_composite_result(evidence_dir, "03-datasource-apply.json", configured, files)
|
|
2038
|
+
else:
|
|
2039
|
+
configure_dry = datasource_configure_command(argparse.Namespace(
|
|
2040
|
+
install_root=args.install_root, data_root=args.data_root, profile=profile, apply=False, replace=False,
|
|
2041
|
+
))
|
|
2042
|
+
save_composite_result(evidence_dir, "02-datasource-dry.json", configure_dry, files)
|
|
2043
|
+
if not args.approve_configure:
|
|
2044
|
+
return {
|
|
2045
|
+
"success": True,
|
|
2046
|
+
"schemaVersion": "foggy-deepseek-datasource-run/v1",
|
|
2047
|
+
"profile": profile,
|
|
2048
|
+
"phaseStatus": "awaiting-configure-approval",
|
|
2049
|
+
"evidenceDir": str(evidence_dir),
|
|
2050
|
+
"evidenceFiles": files,
|
|
2051
|
+
"next": "rerun with --approve-configure after the datasource mutation is approved",
|
|
2052
|
+
"productionReady": False,
|
|
2053
|
+
}
|
|
2054
|
+
configured = datasource_configure_command(argparse.Namespace(
|
|
2055
|
+
install_root=args.install_root, data_root=args.data_root, profile=profile, apply=True, replace=False,
|
|
2056
|
+
))
|
|
2057
|
+
save_composite_result(evidence_dir, "03-datasource-apply.json", configured, files)
|
|
2058
|
+
state = read_onboarding_state(data_root, profile)
|
|
1960
2059
|
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
2060
|
+
if step_completed(state, "datasourceVerified"):
|
|
2061
|
+
bound = resumed_phase(profile, "datasourceVerified")
|
|
2062
|
+
save_composite_result(evidence_dir, "04-datasource-test.json", bound, files)
|
|
2063
|
+
save_composite_result(evidence_dir, "05-datasource-bind.json", bound, files)
|
|
2064
|
+
else:
|
|
2065
|
+
tested = datasource_verify_command(argparse.Namespace(
|
|
2066
|
+
install_root=args.install_root, data_root=args.data_root, profile=profile, bind=False,
|
|
2067
|
+
))
|
|
2068
|
+
save_composite_result(evidence_dir, "04-datasource-test.json", tested, files)
|
|
2069
|
+
if not args.approve_bind:
|
|
2070
|
+
return {
|
|
2071
|
+
"success": True,
|
|
2072
|
+
"schemaVersion": "foggy-deepseek-datasource-run/v1",
|
|
2073
|
+
"profile": profile,
|
|
2074
|
+
"phaseStatus": "awaiting-bind-approval",
|
|
2075
|
+
"evidenceDir": str(evidence_dir),
|
|
2076
|
+
"evidenceFiles": files,
|
|
2077
|
+
"next": "rerun with --approve-configure --approve-bind after namespace binding is approved",
|
|
2078
|
+
"productionReady": False,
|
|
2079
|
+
}
|
|
2080
|
+
bound = datasource_verify_command(argparse.Namespace(
|
|
2081
|
+
install_root=args.install_root, data_root=args.data_root, profile=profile, bind=True,
|
|
2082
|
+
))
|
|
2083
|
+
save_composite_result(evidence_dir, "05-datasource-bind.json", bound, files)
|
|
2084
|
+
state = read_onboarding_state(data_root, profile)
|
|
2085
|
+
|
|
2086
|
+
if step_completed(state, "schemaDiscovered"):
|
|
2087
|
+
schema_step = state["steps"]["schemaDiscovered"]
|
|
2088
|
+
discovered = resumed_phase(
|
|
2089
|
+
profile,
|
|
2090
|
+
"schemaDiscovered",
|
|
2091
|
+
selectedCount=schema_step.get("selectedCount", 0),
|
|
2092
|
+
artifactPath=state.get("artifacts", {}).get("schemaDiscovery"),
|
|
2093
|
+
)
|
|
2094
|
+
else:
|
|
2095
|
+
discovered = schema_discover_command(argparse.Namespace(
|
|
2096
|
+
install_root=args.install_root,
|
|
2097
|
+
data_root=args.data_root,
|
|
2098
|
+
profile=profile,
|
|
2099
|
+
schema=args.schema,
|
|
2100
|
+
pattern=args.pattern,
|
|
2101
|
+
table=args.table,
|
|
2102
|
+
max_tables=args.max_tables,
|
|
2103
|
+
list_only=False,
|
|
2104
|
+
no_views=args.no_views,
|
|
2105
|
+
include_indexes=args.include_indexes,
|
|
2106
|
+
))
|
|
1977
2107
|
save_composite_result(evidence_dir, "06-schema.json", discovered, files)
|
|
1978
2108
|
return {
|
|
1979
2109
|
"success": True,
|
|
@@ -1989,6 +2119,29 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
|
|
|
1989
2119
|
}
|
|
1990
2120
|
|
|
1991
2121
|
|
|
2122
|
+
def semantic_plan_snapshot(state: dict, plan: dict) -> tuple[Path, dict, bool]:
|
|
2123
|
+
project_root = normalized(state["projectRoot"])
|
|
2124
|
+
draft_dir = normalized(project_root / plan["draftDir"])
|
|
2125
|
+
if not is_child(draft_dir, project_root) or draft_dir == project_root:
|
|
2126
|
+
raise OnboardingError("draftDir must stay inside projectRoot and cannot equal it")
|
|
2127
|
+
manifest = semantic_manifest(draft_dir)
|
|
2128
|
+
semantic = state.get("semantic", {})
|
|
2129
|
+
registered = semantic.get("draftManifest") or {}
|
|
2130
|
+
matches = bool(
|
|
2131
|
+
step_completed(state, "semanticDrafted")
|
|
2132
|
+
and normalized(semantic.get("draftDir", draft_dir)) == draft_dir
|
|
2133
|
+
and semantic.get("bundleName") == plan["bundleName"]
|
|
2134
|
+
and semantic.get("queryModels") == plan["queryModels"]
|
|
2135
|
+
and registered.get("digest") == manifest["digest"]
|
|
2136
|
+
)
|
|
2137
|
+
return draft_dir, manifest, matches
|
|
2138
|
+
|
|
2139
|
+
|
|
2140
|
+
def published_digest_matches(state: dict, digest: str) -> bool:
|
|
2141
|
+
published = state.get("steps", {}).get("semanticPublished", {})
|
|
2142
|
+
return published.get("status") == "completed" and published.get("digest") == digest
|
|
2143
|
+
|
|
2144
|
+
|
|
1992
2145
|
def semantic_run_command(args: argparse.Namespace) -> dict:
|
|
1993
2146
|
approved_plan = validate_semantic_plan(read_json_object(normalized(args.semantic_plan), "Semantic plan"))
|
|
1994
2147
|
if not approved_plan.get("profile"):
|
|
@@ -2000,6 +2153,17 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
|
|
|
2000
2153
|
profile_args.profile = profile
|
|
2001
2154
|
state, _install_state, _data_root, _runtime_state = require_profile(profile_args, require_runtime=True)
|
|
2002
2155
|
project_root = normalized(state["projectRoot"])
|
|
2156
|
+
payload_path = normalized(args.query_payload)
|
|
2157
|
+
if not is_child(payload_path, project_root):
|
|
2158
|
+
raise OnboardingError(
|
|
2159
|
+
"Query payload must stay inside projectRoot; place contracts under .foggy/onboarding-contracts before approval"
|
|
2160
|
+
)
|
|
2161
|
+
bounded_query_payload(payload_path)
|
|
2162
|
+
declared_query_model = args.query_model or (approved_plan["queryModels"][0] if len(approved_plan["queryModels"]) == 1 else None)
|
|
2163
|
+
if not declared_query_model:
|
|
2164
|
+
raise OnboardingError("--query-model is required when the semantic plan declares multiple query models")
|
|
2165
|
+
if declared_query_model not in approved_plan["queryModels"]:
|
|
2166
|
+
raise OnboardingError("--query-model must be declared in semanticPlan.queryModels")
|
|
2003
2167
|
contract_evidence = approved_plan.get("evidenceDir")
|
|
2004
2168
|
if contract_evidence and args.evidence_dir:
|
|
2005
2169
|
if normalized(project_root / contract_evidence) != normalized(args.evidence_dir):
|
|
@@ -2007,78 +2171,141 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
|
|
|
2007
2171
|
evidence_dir = composite_evidence_dir(project_root, profile, str(project_root / contract_evidence) if contract_evidence else args.evidence_dir)
|
|
2008
2172
|
files: list[str] = []
|
|
2009
2173
|
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2174
|
+
_draft_dir, manifest, draft_matches = semantic_plan_snapshot(state, approved_plan)
|
|
2175
|
+
published_matches = published_digest_matches(state, manifest["digest"])
|
|
2176
|
+
if draft_matches or published_matches:
|
|
2177
|
+
drafted = resumed_phase(profile, "semanticDrafted", digest=manifest["digest"])
|
|
2178
|
+
else:
|
|
2179
|
+
drafted = semantic_draft_command(argparse.Namespace(
|
|
2180
|
+
install_root=args.install_root,
|
|
2181
|
+
data_root=args.data_root,
|
|
2182
|
+
profile=profile,
|
|
2183
|
+
semantic_plan=args.semantic_plan,
|
|
2184
|
+
))
|
|
2185
|
+
state = read_onboarding_state(normalized(state["dataRoot"]), profile)
|
|
2186
|
+
manifest = state["semantic"]["draftManifest"]
|
|
2016
2187
|
save_composite_result(evidence_dir, "07-semantic-draft.json", drafted, files)
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2188
|
+
state = read_onboarding_state(normalized(state["dataRoot"]), profile)
|
|
2189
|
+
validation_step = state.get("steps", {}).get("semanticValidated", {})
|
|
2190
|
+
published_matches = published_digest_matches(state, manifest["digest"])
|
|
2191
|
+
validation_matches = validation_step.get("status") == "completed" and validation_step.get("digest") == manifest["digest"]
|
|
2192
|
+
if validation_matches or published_matches:
|
|
2193
|
+
if published_matches and not validation_matches:
|
|
2194
|
+
mark_step(state, "semanticValidated", "completed", digest=manifest["digest"], resumedFromPublished=True)
|
|
2195
|
+
write_onboarding_state(normalized(state["dataRoot"]), state)
|
|
2196
|
+
validated = resumed_phase(profile, "semanticValidated", digest=manifest["digest"])
|
|
2197
|
+
save_composite_result(evidence_dir, "08-semantic-validate-dry.json", validated, files)
|
|
2198
|
+
else:
|
|
2199
|
+
validate_dry = semantic_validate_command(argparse.Namespace(
|
|
2200
|
+
install_root=args.install_root,
|
|
2201
|
+
data_root=args.data_root,
|
|
2202
|
+
profile=profile,
|
|
2203
|
+
apply=False,
|
|
2204
|
+
include_stack_trace=False,
|
|
2205
|
+
))
|
|
2206
|
+
save_composite_result(evidence_dir, "08-semantic-validate-dry.json", validate_dry, files)
|
|
2207
|
+
if not args.approve_validate:
|
|
2208
|
+
return {
|
|
2209
|
+
"success": True,
|
|
2210
|
+
"schemaVersion": "foggy-deepseek-semantic-run/v1",
|
|
2211
|
+
"profile": profile,
|
|
2212
|
+
"phaseStatus": "awaiting-validate-approval",
|
|
2213
|
+
"evidenceDir": str(evidence_dir),
|
|
2214
|
+
"evidenceFiles": files,
|
|
2215
|
+
"next": "rerun with --approve-validate after the validation catalog mutation is approved",
|
|
2216
|
+
"productionReady": False,
|
|
2217
|
+
}
|
|
2218
|
+
validated = semantic_validate_command(argparse.Namespace(
|
|
2219
|
+
install_root=args.install_root,
|
|
2220
|
+
data_root=args.data_root,
|
|
2221
|
+
profile=profile,
|
|
2222
|
+
apply=True,
|
|
2223
|
+
include_stack_trace=False,
|
|
2224
|
+
))
|
|
2044
2225
|
save_composite_result(evidence_dir, "09-semantic-validate-apply.json", validated, files)
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2226
|
+
state = read_onboarding_state(normalized(state["dataRoot"]), profile)
|
|
2227
|
+
if published_digest_matches(state, manifest["digest"]):
|
|
2228
|
+
published = resumed_phase(
|
|
2229
|
+
profile,
|
|
2230
|
+
"semanticPublished",
|
|
2231
|
+
digest=manifest["digest"],
|
|
2232
|
+
bundleName=state["semantic"]["bundleName"],
|
|
2233
|
+
)
|
|
2234
|
+
save_composite_result(evidence_dir, "10-semantic-publish-dry.json", published, files)
|
|
2235
|
+
else:
|
|
2236
|
+
publish_dry = semantic_publish_command(argparse.Namespace(
|
|
2237
|
+
install_root=args.install_root,
|
|
2238
|
+
data_root=args.data_root,
|
|
2239
|
+
profile=profile,
|
|
2240
|
+
apply=False,
|
|
2241
|
+
replace_bundle=False,
|
|
2242
|
+
watch=False,
|
|
2243
|
+
prune=False,
|
|
2244
|
+
))
|
|
2245
|
+
save_composite_result(evidence_dir, "10-semantic-publish-dry.json", publish_dry, files)
|
|
2246
|
+
if not args.approve_publish:
|
|
2247
|
+
return {
|
|
2248
|
+
"success": True,
|
|
2249
|
+
"schemaVersion": "foggy-deepseek-semantic-run/v1",
|
|
2250
|
+
"profile": profile,
|
|
2251
|
+
"phaseStatus": "awaiting-publish-approval",
|
|
2252
|
+
"evidenceDir": str(evidence_dir),
|
|
2253
|
+
"evidenceFiles": files,
|
|
2254
|
+
"next": "rerun with --approve-validate --approve-publish after publication is approved",
|
|
2255
|
+
"productionReady": False,
|
|
2256
|
+
}
|
|
2257
|
+
published = semantic_publish_command(argparse.Namespace(
|
|
2258
|
+
install_root=args.install_root,
|
|
2259
|
+
data_root=args.data_root,
|
|
2260
|
+
profile=profile,
|
|
2261
|
+
apply=True,
|
|
2262
|
+
replace_bundle=False,
|
|
2263
|
+
watch=False,
|
|
2264
|
+
prune=False,
|
|
2265
|
+
))
|
|
2266
|
+
save_composite_result(evidence_dir, "11-semantic-publish-apply.json", published, files)
|
|
2267
|
+
state = read_onboarding_state(normalized(state["dataRoot"]), profile)
|
|
2268
|
+
verified_step = state.get("steps", {}).get("semanticVerified", {})
|
|
2269
|
+
payload_digest = sha256(payload_path)
|
|
2270
|
+
if (
|
|
2271
|
+
verified_step.get("status") == "completed"
|
|
2272
|
+
and verified_step.get("queryModel") == declared_query_model
|
|
2273
|
+
and verified_step.get("queryPayloadDigest") == payload_digest
|
|
2274
|
+
):
|
|
2275
|
+
resumed = resumed_phase(
|
|
2276
|
+
profile,
|
|
2277
|
+
"semanticVerified",
|
|
2278
|
+
queryModel=declared_query_model,
|
|
2279
|
+
queryValidated=True,
|
|
2280
|
+
queryExecuted=True,
|
|
2281
|
+
rowCount=verified_step.get("rowCount"),
|
|
2282
|
+
queryPayloadDigest=payload_digest,
|
|
2283
|
+
)
|
|
2284
|
+
save_composite_result(evidence_dir, "12-query-validate.json", resumed, files)
|
|
2285
|
+
save_composite_result(evidence_dir, "13-query-execute.json", resumed, files)
|
|
2286
|
+
status = onboarding_status_command(argparse.Namespace(
|
|
2287
|
+
install_root=args.install_root, data_root=args.data_root, profile=profile,
|
|
2288
|
+
))
|
|
2289
|
+
save_composite_result(evidence_dir, "14-status.json", status, files)
|
|
2056
2290
|
return {
|
|
2057
2291
|
"success": True,
|
|
2058
2292
|
"schemaVersion": "foggy-deepseek-semantic-run/v1",
|
|
2059
2293
|
"profile": profile,
|
|
2060
|
-
"phaseStatus": "
|
|
2294
|
+
"phaseStatus": "completed",
|
|
2295
|
+
"resumed": True,
|
|
2296
|
+
"queryModel": declared_query_model,
|
|
2297
|
+
"queryValidated": True,
|
|
2298
|
+
"queryExecuted": True,
|
|
2299
|
+
"rowCount": verified_step.get("rowCount"),
|
|
2061
2300
|
"evidenceDir": str(evidence_dir),
|
|
2062
2301
|
"evidenceFiles": files,
|
|
2063
|
-
"next": "rerun with --approve-validate --approve-publish after publication is approved",
|
|
2064
2302
|
"productionReady": False,
|
|
2065
2303
|
}
|
|
2066
|
-
|
|
2067
|
-
published = semantic_publish_command(argparse.Namespace(
|
|
2068
|
-
install_root=args.install_root,
|
|
2069
|
-
data_root=args.data_root,
|
|
2070
|
-
profile=profile,
|
|
2071
|
-
apply=True,
|
|
2072
|
-
replace_bundle=False,
|
|
2073
|
-
watch=False,
|
|
2074
|
-
prune=False,
|
|
2075
|
-
))
|
|
2076
|
-
save_composite_result(evidence_dir, "11-semantic-publish-apply.json", published, files)
|
|
2077
2304
|
query_validated = semantic_verify_command(argparse.Namespace(
|
|
2078
2305
|
install_root=args.install_root,
|
|
2079
2306
|
data_root=args.data_root,
|
|
2080
2307
|
profile=profile,
|
|
2081
|
-
query_model=
|
|
2308
|
+
query_model=declared_query_model,
|
|
2082
2309
|
query_payload=args.query_payload,
|
|
2083
2310
|
execute=False,
|
|
2084
2311
|
))
|
|
@@ -2101,7 +2328,7 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
|
|
|
2101
2328
|
install_root=args.install_root,
|
|
2102
2329
|
data_root=args.data_root,
|
|
2103
2330
|
profile=profile,
|
|
2104
|
-
query_model=
|
|
2331
|
+
query_model=declared_query_model,
|
|
2105
2332
|
query_payload=args.query_payload,
|
|
2106
2333
|
execute=True,
|
|
2107
2334
|
))
|
|
@@ -2280,13 +2507,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2280
2507
|
status = sub.add_parser("onboard-status")
|
|
2281
2508
|
status.add_argument("--install-root")
|
|
2282
2509
|
status.add_argument("--data-root")
|
|
2283
|
-
status.add_argument("--profile"
|
|
2510
|
+
status.add_argument("--profile")
|
|
2284
2511
|
status.set_defaults(handler=onboarding_status_command)
|
|
2285
2512
|
|
|
2286
2513
|
resume = sub.add_parser("onboard-resume")
|
|
2287
2514
|
resume.add_argument("--install-root")
|
|
2288
2515
|
resume.add_argument("--data-root")
|
|
2289
|
-
resume.add_argument("--profile"
|
|
2516
|
+
resume.add_argument("--profile")
|
|
2290
2517
|
resume.set_defaults(handler=onboarding_resume_command)
|
|
2291
2518
|
|
|
2292
2519
|
datasource_run = sub.add_parser("onboard-datasource-run")
|
|
@@ -2322,7 +2549,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2322
2549
|
datasource_configure = sub.add_parser("datasource-configure")
|
|
2323
2550
|
datasource_configure.add_argument("--install-root")
|
|
2324
2551
|
datasource_configure.add_argument("--data-root")
|
|
2325
|
-
datasource_configure.add_argument("--profile"
|
|
2552
|
+
datasource_configure.add_argument("--profile")
|
|
2326
2553
|
datasource_configure.add_argument("--apply", action="store_true")
|
|
2327
2554
|
datasource_configure.add_argument("--replace", action="store_true")
|
|
2328
2555
|
datasource_configure.set_defaults(handler=datasource_configure_command)
|
|
@@ -2330,14 +2557,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2330
2557
|
datasource_verify = sub.add_parser("datasource-verify")
|
|
2331
2558
|
datasource_verify.add_argument("--install-root")
|
|
2332
2559
|
datasource_verify.add_argument("--data-root")
|
|
2333
|
-
datasource_verify.add_argument("--profile"
|
|
2560
|
+
datasource_verify.add_argument("--profile")
|
|
2334
2561
|
datasource_verify.add_argument("--bind", action="store_true")
|
|
2335
2562
|
datasource_verify.set_defaults(handler=datasource_verify_command)
|
|
2336
2563
|
|
|
2337
2564
|
schema_discover = sub.add_parser("schema-discover")
|
|
2338
2565
|
schema_discover.add_argument("--install-root")
|
|
2339
2566
|
schema_discover.add_argument("--data-root")
|
|
2340
|
-
schema_discover.add_argument("--profile"
|
|
2567
|
+
schema_discover.add_argument("--profile")
|
|
2341
2568
|
schema_discover.add_argument("--schema", action="append")
|
|
2342
2569
|
schema_discover.add_argument("--pattern")
|
|
2343
2570
|
schema_discover.add_argument("--table", action="append")
|
|
@@ -2350,14 +2577,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2350
2577
|
semantic_draft = sub.add_parser("semantic-draft")
|
|
2351
2578
|
semantic_draft.add_argument("--install-root")
|
|
2352
2579
|
semantic_draft.add_argument("--data-root")
|
|
2353
|
-
semantic_draft.add_argument("--profile"
|
|
2580
|
+
semantic_draft.add_argument("--profile")
|
|
2354
2581
|
semantic_draft.add_argument("--semantic-plan", required=True)
|
|
2355
2582
|
semantic_draft.set_defaults(handler=semantic_draft_command)
|
|
2356
2583
|
|
|
2357
2584
|
semantic_validate = sub.add_parser("semantic-validate")
|
|
2358
2585
|
semantic_validate.add_argument("--install-root")
|
|
2359
2586
|
semantic_validate.add_argument("--data-root")
|
|
2360
|
-
semantic_validate.add_argument("--profile"
|
|
2587
|
+
semantic_validate.add_argument("--profile")
|
|
2361
2588
|
semantic_validate.add_argument("--apply", action="store_true")
|
|
2362
2589
|
semantic_validate.add_argument("--include-stack-trace", action="store_true")
|
|
2363
2590
|
semantic_validate.set_defaults(handler=semantic_validate_command)
|
|
@@ -2365,7 +2592,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2365
2592
|
semantic_publish = sub.add_parser("semantic-publish")
|
|
2366
2593
|
semantic_publish.add_argument("--install-root")
|
|
2367
2594
|
semantic_publish.add_argument("--data-root")
|
|
2368
|
-
semantic_publish.add_argument("--profile"
|
|
2595
|
+
semantic_publish.add_argument("--profile")
|
|
2369
2596
|
semantic_publish.add_argument("--apply", action="store_true")
|
|
2370
2597
|
semantic_publish.add_argument("--replace-bundle", action="store_true")
|
|
2371
2598
|
semantic_publish.add_argument("--watch", action="store_true")
|
|
@@ -2375,7 +2602,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2375
2602
|
semantic_verify = sub.add_parser("semantic-verify")
|
|
2376
2603
|
semantic_verify.add_argument("--install-root")
|
|
2377
2604
|
semantic_verify.add_argument("--data-root")
|
|
2378
|
-
semantic_verify.add_argument("--profile"
|
|
2605
|
+
semantic_verify.add_argument("--profile")
|
|
2379
2606
|
semantic_verify.add_argument("--query-model")
|
|
2380
2607
|
semantic_verify.add_argument("--query-payload", required=True)
|
|
2381
2608
|
semantic_verify.add_argument("--execute", action="store_true")
|