@tiangong-lca/cli 0.0.23 → 0.0.25
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 +48 -8
- package/dist/src/cli.js +213 -12
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-alias-request.js +99 -0
- package/dist/src/lib/dataset-maintenance-alias-request.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-apply.js +247 -337
- package/dist/src/lib/dataset-maintenance-apply.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-contract.js +118 -16
- package/dist/src/lib/dataset-maintenance-contract.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-derivatives.js +265 -0
- package/dist/src/lib/dataset-maintenance-derivatives.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-plan.js +38 -6
- package/dist/src/lib/dataset-maintenance-plan.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-protected-contract.js +918 -0
- package/dist/src/lib/dataset-maintenance-protected-contract.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-run.js +771 -0
- package/dist/src/lib/dataset-maintenance-protected-run.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-protected-verify.js +435 -0
- package/dist/src/lib/dataset-maintenance-protected-verify.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-remote.js +140 -1
- package/dist/src/lib/dataset-maintenance-remote.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-verify.js +309 -3
- package/dist/src/lib/dataset-maintenance-verify.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@ checkPaths:
|
|
|
17
17
|
- bin/**
|
|
18
18
|
- src/cli.ts
|
|
19
19
|
- src/main.ts
|
|
20
|
-
lastReviewedAt: 2026-07-
|
|
21
|
-
lastReviewedCommit:
|
|
20
|
+
lastReviewedAt: 2026-07-15
|
|
21
|
+
lastReviewedCommit: ca0cdd7549cad9003d08fb338223ba74682955ae
|
|
22
22
|
---
|
|
23
23
|
|
|
24
24
|
# TianGong LCA CLI
|
|
@@ -29,6 +29,10 @@ Review note, 2026-07-12: `dataset maintenance plan/apply/verify` provides curren
|
|
|
29
29
|
|
|
30
30
|
Review note, 2026-07-13: maintenance scans now prove exact-count pagination even when PostgREST returns fewer rows than the requested `--page-size`. An incomplete or inconsistent scan fails before artifacts, approval, or mutation; under stable filtered membership/order the proof represents a complete ordered multi-request traversal, not one transaction-level/MVCC snapshot.
|
|
31
31
|
|
|
32
|
+
Review note, 2026-07-14: maintenance now includes the protected derivative-only `rebuild-derivatives` operation. V1 plans exactly one current-owner state-0 process with `action=rebuild_derivatives`, `target_mode=owner_draft`, and components `extracted_md` plus `embedding_ft`. Apply only proves guarded-RPC admission (`accepted`/`queued`); independent verify reports `pending`, `passed`, or `failed`.
|
|
33
|
+
|
|
34
|
+
Review note, 2026-07-15: `dataset maintenance run-protected` adds a production-only path for one sealed private alias execution and its exact 50-target derivative closure. The protected executor is server-dispatched and fenced by the authenticated owner plus exact actor/user_id/state_code=0 and plan-closure checks; RLS remains a defense on public and independent-read surfaces. It performs one server preflight, writes an immutable local attempt marker before one admission POST, and requires status-only recovery after any marker or ambiguous response. It has no dev, legacy-alias, publication, or state-code fallback.
|
|
35
|
+
|
|
32
36
|
## Run
|
|
33
37
|
|
|
34
38
|
One-off published run:
|
|
@@ -278,8 +282,10 @@ tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数
|
|
|
278
282
|
tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir /abs/path/to/evidence-search --json
|
|
279
283
|
tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id>@<old-version> --to flow:<new-id>@<new-version> --out-dir /abs/path/to/dataset-rewrite --json
|
|
280
284
|
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir /abs/path/to/dataset-maintenance --page-size 1000 --timeout-ms 10000 --json
|
|
285
|
+
tiangong-lca dataset maintenance plan --scope ./derivative-rebuild-scope.json --operation rebuild-derivatives --out-dir /abs/path/to/derivative-rebuild --json
|
|
281
286
|
tiangong-lca dataset maintenance apply --plan /abs/path/to/dataset-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm <current-account-email> --timeout-ms 10000 --json
|
|
282
287
|
tiangong-lca dataset maintenance verify --plan /abs/path/to/dataset-maintenance/maintenance-plan.json --out-dir /abs/path/to/dataset-maintenance/verify --page-size 1000 --timeout-ms 10000 --json
|
|
288
|
+
tiangong-lca dataset maintenance run-protected --plan /abs/path/to/maintenance-plan.json --freeze /abs/path/to/protected-execution-seal.json --approval /abs/path/to/protected-approval.json --out-dir /abs/path/to/protected-run --status-only --json
|
|
283
289
|
tiangong-lca lifecyclemodel auto-build --input ./examples/lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run --json
|
|
284
290
|
tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run --json
|
|
285
291
|
tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run --json
|
|
@@ -324,12 +330,12 @@ For `dataset references rewrite`, `--commit` executes the state-aware save-draft
|
|
|
324
330
|
|
|
325
331
|
## Dataset Maintenance
|
|
326
332
|
|
|
327
|
-
`dataset maintenance plan/apply/verify` is the row-level cleanup surface for bad imports
|
|
333
|
+
`dataset maintenance plan/apply/run-protected/verify` is the row-level cleanup surface for bad imports, the fixed BAFU private alias rewrite, and protected derivative rebuilds. Ordinary planning, apply, and independent verification use the authenticated account and RLS. The protected executor is server-dispatched and additionally enforces the sealed actor, user_id, state_code=0, exact target set, and closure hashes on every write.
|
|
328
334
|
|
|
329
335
|
```bash
|
|
330
336
|
tiangong-lca dataset maintenance plan \
|
|
331
337
|
--scope ./maintenance-scope.json \
|
|
332
|
-
--operation
|
|
338
|
+
--operation repair-references \
|
|
333
339
|
--out-dir ./dataset-maintenance \
|
|
334
340
|
--page-size 1000 \
|
|
335
341
|
--timeout-ms 10000 \
|
|
@@ -349,8 +355,39 @@ tiangong-lca dataset maintenance verify \
|
|
|
349
355
|
--page-size 1000 \
|
|
350
356
|
--timeout-ms 10000 \
|
|
351
357
|
--json
|
|
358
|
+
|
|
359
|
+
tiangong-lca dataset maintenance run-protected \
|
|
360
|
+
--plan ./protected-step2/maintenance-plan.json \
|
|
361
|
+
--freeze ./protected-step2/protected-execution-seal.json \
|
|
362
|
+
--approval ./protected-step2/protected-approval.json \
|
|
363
|
+
--out-dir ./protected-step2/run \
|
|
364
|
+
--commit \
|
|
365
|
+
--approve-execution <approved-execution-sha256> \
|
|
366
|
+
--confirm <current-account-email> \
|
|
367
|
+
--wait-seconds 60 \
|
|
368
|
+
--poll-ms 10000 \
|
|
369
|
+
--page-size 1000 \
|
|
370
|
+
--timeout-ms 10000 \
|
|
371
|
+
--json
|
|
372
|
+
|
|
373
|
+
tiangong-lca dataset maintenance run-protected \
|
|
374
|
+
--plan ./protected-step2/maintenance-plan.json \
|
|
375
|
+
--freeze ./protected-step2/protected-execution-seal.json \
|
|
376
|
+
--approval ./protected-step2/protected-approval.json \
|
|
377
|
+
--out-dir ./protected-step2/run \
|
|
378
|
+
--status-only \
|
|
379
|
+
--wait-seconds 60 \
|
|
380
|
+
--json
|
|
352
381
|
```
|
|
353
382
|
|
|
383
|
+
`run-protected` is a separate one-shot path for an already reviewed and sealed production execution; it does not replace ordinary planning. Both modes require the exact plan, freeze/seal, approval artifact, and private output directory. Commit mode additionally requires `--commit`, the exact approved execution identity through `--approve-execution`, and the authenticated account email through `--confirm`. `--status-only` is mutually exclusive with `--commit` and performs no preflight or admission.
|
|
384
|
+
|
|
385
|
+
Before requesting preflight, the command validates the sealed production project, full current-user RLS before-state, support closure, and exact derivative baseline. The server then returns the three expected gate digests and a token valid for at most 180 seconds; the CLI captures and compares the live gate receipts before admission. The server-dispatched write remains fenced to the authenticated actor's exact `user_id`, `state_code=0` rows and sealed plan/closure; independent readback still uses RLS. The CLI writes an immutable local submission marker and sends at most one admission POST. A marker, admission timeout, connection loss, or ambiguous admission response permanently switches that local run to status-only recovery; status-read failures may be polled only within the configured wait window and never cause a second admission or fallback to dev or the legacy whole-plan RPC. The default status polling interval is 10 seconds.
|
|
386
|
+
|
|
387
|
+
Success requires the terminal database proof and independent RLS readback to agree on the approved execution, exact row/exchange/audit closure, and exactly 50 derivative targets split into 23 flows and 27 processes. `pending`, `failed`, and `indeterminate` all return a non-zero exit status. The protected operation keeps all affected rows private to their owner, changes no `state_code`, and does not publish data.
|
|
388
|
+
|
|
389
|
+
For the derivative-only profile, use the same three commands with `--operation rebuild-derivatives`. Its scope must contain exactly one `processes` action with `action: "rebuild_derivatives"`, `target_mode: "owner_draft"`, expected current owner, expected `state_code: 0`, and the exact component set `extracted_md` plus `embedding_ft`.
|
|
390
|
+
|
|
354
391
|
`--page-size` accepts `1-5000` and is only the requested maximum. PostgREST may enforce a lower server-side cap. The CLI requests `Prefer: count=exact`, validates the exact total and returned range from each `Content-Range`, advances the next offset by the number of rows actually returned, and requires strict `id`/`version` ordering without missing or duplicate identities. Each accepted scan records per-table requested/effective page size, page count, rows fetched, exact total, and aggregate entity counts.
|
|
355
392
|
|
|
356
393
|
This completeness proof means the CLI traversed the filtered result while that table's membership and ordering keys remained stable. Because the tables are read through multiple HTTP requests, it is not a transaction-level or MVCC snapshot of one instant; same-cardinality delete/insert churn can evade total and ordering checks. Plan hashes and apply-time drift checks provide the later mutation guard, and operators must avoid concurrent maintenance of the same account while planning or clearing it.
|
|
@@ -358,18 +395,21 @@ This completeness proof means the CLI traversed the filtered result while that t
|
|
|
358
395
|
The scope is intentionally narrow:
|
|
359
396
|
|
|
360
397
|
- Each requested row must name its table, exact `id`, exact `version`, expected current owner, and draft `state_code=0` state.
|
|
361
|
-
- `--operation` accepts `delete`, `retire`, `redo-import`, `repair-references`,
|
|
398
|
+
- `--operation` accepts `delete`, `retire`, `redo-import`, `repair-references`, `merge-support-aliases`, or `rebuild-derivatives`; it records the operator's maintenance intent and does not broaden the eligible row actions.
|
|
362
399
|
- Only current-user `contacts`, `sources`, `flows`, and `processes` can become `save_draft` or `delete` actions.
|
|
363
400
|
- `merge-support-aliases` requires top-level `target_mode: "owner_draft"` and accepts only two named batches, `time` and `length_time`. The scope must bind reviewed current-owner draft source and target FP/UG exact ids/versions to 52 `update_json_ordered` actions: 25 time rows (1 FP, 10 flows, 14 processes) and 27 length-time rows (1 FP, 13 flows, 13 processes). Process actions freeze every selected exchange index, internal id, flow id/version, direction, before hash, and both amount strings.
|
|
364
401
|
- The alias factors are exact decimal strings: `0.00011415525114155251` for time and `1000` for length-time. Planning requires exactly 20 and 39 selected exchanges, preserves exactly 309 other exchanges in the affected processes, and proves the fixed source-zero/target-reference postconditions. The transformation changes references and the selected `meanAmount`/`resultingAmount`; it does not delete the source FP/UG rows.
|
|
365
402
|
- Source alias support, target FP/UG, and every changed flow/process must all belong to the authenticated account at `state_code=0`. Public/shared, foreign-owner, mixed-visibility, non-draft, lifecyclemodel, and unsupported action/table rows remain protected.
|
|
403
|
+
- `rebuild-derivatives` accepts exactly one exact-version `processes` row and is bidirectionally bound to `action=rebuild_derivatives`, `target_mode=owner_draft`, and components `extracted_md` plus `embedding_ft`. It cannot target a public/shared row, a foreign owner, a non-draft row, another table, multiple actions, or a partial/different component set. It rebuilds derivatives only; the primary process payload, owner/state, and `modified_at` remain unchanged.
|
|
366
404
|
- The CLI classifies and executes an operator-authored scope; it does not decide whether rows are semantically duplicates, canonical replacements, or safe business-level cleanup targets.
|
|
367
405
|
|
|
368
|
-
`plan` accepts the account scan only after its exact-count proof is complete, then writes the frozen `maintenance-scope.json`, `rls-visible-snapshot.json`, `protected-rows.jsonl`, `reference-impact-report.json`, `maintenance-plan.json`, and `dry-run-report.json`. The snapshot, dry-run report, and newly generated plan carry the aggregate completeness proof, so it is bound into the plan SHA-256. Alias plans additionally write `exchange-rewrite-plan.jsonl`, freeze current-owner state-0 target FP, target UG, and source UG snapshots for each batch, derive schema-valid desired payloads with matching embedded UUID/version, and include the exact closure, `modified_at`, hashes, conversion evidence, and postconditions in the approved plan. The plan SHA-256 is the approval identity; do not edit or recompute the plan after review.
|
|
406
|
+
`plan` accepts the account scan only after its exact-count proof is complete, then writes the frozen `maintenance-scope.json`, `rls-visible-snapshot.json`, `protected-rows.jsonl`, `reference-impact-report.json`, `maintenance-plan.json`, and `dry-run-report.json`. The snapshot, dry-run report, and newly generated plan carry the aggregate completeness proof, so it is bound into the plan SHA-256. Alias plans additionally write `exchange-rewrite-plan.jsonl`, freeze current-owner state-0 target FP, target UG, and source UG snapshots for each batch, derive schema-valid desired payloads with matching embedded UUID/version, and include the exact closure, `modified_at`, hashes, conversion evidence, and postconditions in the approved plan. A derivative rebuild plan additionally obtains a database-produced snapshot for only the exact target action and binds its primary and derivative preconditions into the plan; large markdown/vector fields are not added to the account-wide scan. The plan SHA-256 is the approval identity; do not edit or recompute the plan after review.
|
|
407
|
+
|
|
408
|
+
`apply` is write-disabled unless all three commit guards are present: `--commit`, `--approve-plan <sha256>`, and `--confirm <current-account-email>`. Before approval is persisted or any write runs, it requires a fresh complete exact-count account scan and re-checks the whole plan for drift; the current completeness proof is recorded in `approval-record.json`. Ordinary draft updates/deletes use their platform paths. The original V1 alias adapter retains its frozen request and artifact contract for compatibility, but it is not an authorized execution or recovery fallback for a sealed production `merge-support-aliases` plan. That plan must use `run-protected`, whose database contract replaces replay with one durable attempt/admission identity.
|
|
369
409
|
|
|
370
|
-
`
|
|
410
|
+
For `rebuild-derivatives`, apply submits the frozen single-action plan only to the authenticated guarded RPC. The database admission envelope must report `queued`; the CLI records that durable admission as an `accepted` action with queued proof. It does not mean markdown or embedding generation has completed. Replay must return the same durable request/proof rather than enqueueing a second rebuild. There is no fallback to a direct Edge call, `admin embedding-run`, a raw queue, SQL, service-role credentials, or raw REST mutation.
|
|
371
411
|
|
|
372
|
-
`verify` requires another complete exact-count account readback rather than trusting the apply report, records its completeness proof, and writes `readback-verify-report.json` in its own output directory. For alias plans it also requires both successful batch records, all 52 correlated row records, all 59 unique exchange records, unchanged support snapshots, and exact desired row payloads. It validates the RPC-returned audit ids against the local proof chain; it does not independently query `public.command_audit_log`.
|
|
412
|
+
`verify` requires another complete exact-count account readback rather than trusting the apply report, records its completeness proof, and writes `readback-verify-report.json` in its own output directory. For alias plans it also requires both successful batch records, all 52 correlated row records, all 59 unique exchange records, unchanged support snapshots, and exact desired row payloads. It validates the RPC-returned audit ids against the local proof chain; it does not independently query `public.command_audit_log`. For derivative rebuild plans, verify reads the durable request plus a fresh action-scoped process snapshot and reports only `pending`, `passed`, or `failed`. Database statuses `queued`, `dispatching`, `markdown_pending`, and `embedding_pending` map to `pending`; `completed` maps to `passed` only when both requested derivatives are current and every frozen primary-field precondition remains unchanged; `stale` and `failed` map to `failed`. The raw status proof, including `phase` and `fence_active`, is preserved in the report. A failed rebuild does not by itself prove that the primary-row write fence has been released.
|
|
373
413
|
|
|
374
414
|
`dataset maintenance clear-account` uses the same exact-count rule for its initial five-table snapshot, per-table commit checks, and a final fresh scan of all five tables. It reports `cleared_account` only when that final aggregate proof exists with `row_count=0`; if the final proof fails after deletions begin, it still writes a `completed_with_failures` audit report. If the initial scan cannot prove completeness, it writes no snapshot or approval artifact and performs zero deletes.
|
|
375
415
|
|
package/dist/src/cli.js
CHANGED
|
@@ -56,6 +56,7 @@ import { runDatasetClassificationApply, runDatasetClassificationAudit, runDatase
|
|
|
56
56
|
import { runDatasetMaintenanceClearAccount, } from './lib/dataset-maintenance-clear-account.js';
|
|
57
57
|
import { runDatasetMaintenancePlan } from './lib/dataset-maintenance-plan.js';
|
|
58
58
|
import { runDatasetMaintenanceApply } from './lib/dataset-maintenance-apply.js';
|
|
59
|
+
import { runDatasetMaintenanceProtected } from './lib/dataset-maintenance-protected-run.js';
|
|
59
60
|
import { runDatasetMaintenanceVerify } from './lib/dataset-maintenance-verify.js';
|
|
60
61
|
import { runDatasetSourceUploadAttachments, } from './lib/dataset-source-upload-attachments.js';
|
|
61
62
|
function renderMainHelp(dotEnvStatus) {
|
|
@@ -131,6 +132,7 @@ Examples:
|
|
|
131
132
|
tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id>@<old-version> --to flow:<new-id>@<new-version> --out-dir /abs/path/to/dataset-rewrite
|
|
132
133
|
tiangong-lca dataset maintenance clear-account --out-dir /abs/path/to/account-clear --json
|
|
133
134
|
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir /abs/path/to/dataset-maintenance
|
|
135
|
+
tiangong-lca dataset maintenance run-protected --plan ./maintenance-plan.json --freeze ./protected-execution-seal.json --approval ./protected-approval.json --out-dir /abs/path/to/protected-run --status-only
|
|
134
136
|
tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
|
|
135
137
|
tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
136
138
|
tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
@@ -283,6 +285,7 @@ Implemented Subcommands:
|
|
|
283
285
|
maintenance clear-account Dry-run or clear current authenticated account-owned dataset rows through RLS
|
|
284
286
|
maintenance plan Build an immutable, RLS-visible row-level maintenance plan
|
|
285
287
|
maintenance apply Execute an explicitly approved maintenance plan through current-user RLS
|
|
288
|
+
maintenance run-protected Run or inspect one sealed, one-shot production maintenance execution
|
|
286
289
|
maintenance verify Read back affected rows and references against the immutable plan
|
|
287
290
|
|
|
288
291
|
Examples:
|
|
@@ -310,21 +313,25 @@ Examples:
|
|
|
310
313
|
tiangong-lca dataset references refresh-remote --input ./rows.jsonl --out ./rows.refreshed.jsonl --out-dir ./dataset-reference-refresh --help
|
|
311
314
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json --help
|
|
312
315
|
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir ./dataset-maintenance --help
|
|
316
|
+
tiangong-lca dataset maintenance run-protected --help
|
|
313
317
|
`.trim();
|
|
314
318
|
}
|
|
315
319
|
function renderDatasetMaintenanceHelp() {
|
|
316
320
|
return `Usage:
|
|
317
|
-
tiangong-lca dataset maintenance <clear-account|plan|apply|verify> [options]
|
|
321
|
+
tiangong-lca dataset maintenance <clear-account|plan|apply|run-protected|verify> [options]
|
|
318
322
|
|
|
319
323
|
Actions:
|
|
320
324
|
clear-account Dry-run or delete current authenticated account-owned lifecyclemodels, processes, flows, sources, and contacts.
|
|
321
325
|
plan Build an immutable maintenance plan from a scope manifest, visible remote snapshot, dependency impact report, and intended operation.
|
|
322
|
-
apply Execute an approved plan through current-user RLS and platform dataset command paths
|
|
323
|
-
|
|
326
|
+
apply Execute or durably admit an ordinary approved plan through current-user RLS and platform dataset command paths.
|
|
327
|
+
run-protected Run or inspect one sealed production execution with one-shot admission and terminal derivative proof.
|
|
328
|
+
verify Re-fetch rows, references, or derivative request state and report passed, pending, or failed independently of apply.
|
|
324
329
|
|
|
325
330
|
Safety:
|
|
326
331
|
plan and verify are read-only.
|
|
327
332
|
apply is commit-only and requires --commit, the exact plan SHA-256 via --approve-plan, and the current account email via --confirm.
|
|
333
|
+
A sealed production merge-support-aliases execution must use run-protected; apply is not its fallback.
|
|
334
|
+
run-protected is production-only: authenticated owner context plus server-side actor/user_id/state_code=0 and exact-plan closure fences protect writes; RLS remains a defense on public and independent-read surfaces. It never falls back to dev, a legacy alias RPC, or a second admission POST.
|
|
328
335
|
|
|
329
336
|
Required Artifact Contract:
|
|
330
337
|
- maintenance-plan.json
|
|
@@ -334,12 +341,15 @@ Required Artifact Contract:
|
|
|
334
341
|
- dry-run-report.json
|
|
335
342
|
- commit-report.json
|
|
336
343
|
- readback-verify-report.json
|
|
344
|
+
run-protected uses a separate immutable protected-execution seal, submission marker, append-only status ledger, and terminal report.
|
|
337
345
|
|
|
338
346
|
Examples:
|
|
339
347
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json
|
|
340
348
|
tiangong-lca dataset maintenance clear-account --commit --confirm user@example.com --out-dir ./account-clear
|
|
341
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation
|
|
349
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation repair-references --out-dir ./dataset-maintenance
|
|
350
|
+
tiangong-lca dataset maintenance plan --scope ./derivative-rebuild-scope.json --operation rebuild-derivatives --out-dir ./derivative-rebuild
|
|
342
351
|
tiangong-lca dataset maintenance apply --plan ./dataset-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm user@example.com
|
|
352
|
+
tiangong-lca dataset maintenance run-protected --plan ./maintenance-plan.json --freeze ./protected-execution-seal.json --approval ./protected-approval.json --out-dir ./protected-run --status-only
|
|
343
353
|
tiangong-lca dataset maintenance verify --plan ./dataset-maintenance/maintenance-plan.json --out-dir ./dataset-maintenance/verify
|
|
344
354
|
`.trim();
|
|
345
355
|
}
|
|
@@ -348,7 +358,7 @@ function renderDatasetMaintenancePlanHelp() {
|
|
|
348
358
|
tiangong-lca dataset maintenance plan --scope <file> --operation <operation> --out-dir <dir> [options]
|
|
349
359
|
|
|
350
360
|
Operations:
|
|
351
|
-
delete | retire | redo-import | repair-references | merge-support-aliases
|
|
361
|
+
delete | retire | redo-import | repair-references | merge-support-aliases | rebuild-derivatives
|
|
352
362
|
|
|
353
363
|
Options:
|
|
354
364
|
--scope <file> Maintenance scope manifest
|
|
@@ -360,7 +370,8 @@ Options:
|
|
|
360
370
|
-h, --help
|
|
361
371
|
|
|
362
372
|
Outputs written under --out-dir include the immutable maintenance-plan.json, visible snapshot,
|
|
363
|
-
protected-row ledger, reference-impact report, and dry-run report.
|
|
373
|
+
protected-row ledger, reference-impact report, and dry-run report. rebuild-derivatives additionally
|
|
374
|
+
freezes one action-scoped database snapshot without expanding the account scan with vector data.
|
|
364
375
|
`.trim();
|
|
365
376
|
}
|
|
366
377
|
function renderDatasetMaintenanceApplyHelp() {
|
|
@@ -370,6 +381,8 @@ function renderDatasetMaintenanceApplyHelp() {
|
|
|
370
381
|
Behavior:
|
|
371
382
|
Commit-only. The command rejects dry-run mode, a missing --commit flag, a plan hash mismatch,
|
|
372
383
|
or a confirmation email that does not match the current authenticated account.
|
|
384
|
+
For rebuild-derivatives, success means guarded admission is queued; it never means derivatives completed.
|
|
385
|
+
Sealed production merge-support-aliases executions must use run-protected; this command is not a fallback.
|
|
373
386
|
|
|
374
387
|
Options:
|
|
375
388
|
--plan <file> Immutable maintenance-plan.json
|
|
@@ -380,7 +393,46 @@ Options:
|
|
|
380
393
|
--json Print compact JSON
|
|
381
394
|
-h, --help
|
|
382
395
|
|
|
383
|
-
Outputs include approval-record.json and commit-report.json alongside an append-only action ledger.
|
|
396
|
+
Outputs include approval-record.json and commit-report.json alongside an append-only action or admission ledger.
|
|
397
|
+
`.trim();
|
|
398
|
+
}
|
|
399
|
+
function renderDatasetMaintenanceRunProtectedHelp() {
|
|
400
|
+
return `Usage:
|
|
401
|
+
tiangong-lca dataset maintenance run-protected --plan <file> --freeze <file> --approval <file> --out-dir <dir> --commit --approve-execution <sha256> --confirm <email> [options]
|
|
402
|
+
tiangong-lca dataset maintenance run-protected --plan <file> --freeze <file> --approval <file> --out-dir <dir> --status-only [options]
|
|
403
|
+
|
|
404
|
+
Behavior:
|
|
405
|
+
Runs one sealed, server-dispatched production maintenance execution fenced to the authenticated actor's
|
|
406
|
+
exact owner-draft target set, or reads durable status through an auth.uid-, actor-, and plan-fenced RPC
|
|
407
|
+
without admitting work; only the independent table readback uses RLS.
|
|
408
|
+
Commit and status-only modes are mutually exclusive. The commit path validates the full private
|
|
409
|
+
before-state, accepts only server-derived gates within the 180-second preflight window, writes an immutable
|
|
410
|
+
local submission marker, and sends at most one admission POST. After a marker or ambiguous response,
|
|
411
|
+
use --status-only; the command never retries admission or falls back to dev or the legacy alias RPC.
|
|
412
|
+
|
|
413
|
+
Required in both modes:
|
|
414
|
+
--plan <file> Immutable maintenance-plan.json
|
|
415
|
+
--freeze <file> Protected production execution seal/freeze artifact
|
|
416
|
+
--approval <file> Exact human-approval binding artifact
|
|
417
|
+
--out-dir <dir> Private protected-run artifact directory
|
|
418
|
+
|
|
419
|
+
Commit-only guards:
|
|
420
|
+
--commit Submit the sealed execution exactly once
|
|
421
|
+
--approve-execution <sha256> Exact approved execution identity SHA-256
|
|
422
|
+
--confirm <email> Current authenticated account email
|
|
423
|
+
|
|
424
|
+
Recovery:
|
|
425
|
+
--status-only Read/poll and independently verify the sealed request; never preflight or admit
|
|
426
|
+
|
|
427
|
+
Options:
|
|
428
|
+
--wait-seconds <n> Maximum terminal-status wait in seconds; 0 performs one status read
|
|
429
|
+
--poll-ms <n> Positive polling interval in milliseconds; default 10000
|
|
430
|
+
--page-size <n> Requested RLS readback page size, 1-5000
|
|
431
|
+
--timeout-ms <n> Positive request timeout in milliseconds
|
|
432
|
+
--json Print compact JSON
|
|
433
|
+
-h, --help
|
|
434
|
+
|
|
435
|
+
Only a terminal passed proof exits successfully. pending, failed, and indeterminate return non-zero.
|
|
384
436
|
`.trim();
|
|
385
437
|
}
|
|
386
438
|
function renderDatasetMaintenanceVerifyHelp() {
|
|
@@ -395,7 +447,8 @@ Options:
|
|
|
395
447
|
--json Print compact JSON
|
|
396
448
|
-h, --help
|
|
397
449
|
|
|
398
|
-
Outputs include readback-verify-report.json
|
|
450
|
+
Outputs include readback-verify-report.json. rebuild-derivatives reports pending, passed, or failed;
|
|
451
|
+
pending and failed both return a non-zero exit status.
|
|
399
452
|
`.trim();
|
|
400
453
|
}
|
|
401
454
|
function renderDatasetMaintenanceClearAccountHelp() {
|
|
@@ -3036,6 +3089,19 @@ function parseDatasetMaintenancePositiveInteger(value, flagName) {
|
|
|
3036
3089
|
}
|
|
3037
3090
|
return Number.parseInt(value.trim(), 10);
|
|
3038
3091
|
}
|
|
3092
|
+
function parseDatasetMaintenanceNonNegativeInteger(value, flagName) {
|
|
3093
|
+
if (typeof value !== 'string') {
|
|
3094
|
+
return undefined;
|
|
3095
|
+
}
|
|
3096
|
+
if (!/^\d+$/u.test(value.trim())) {
|
|
3097
|
+
throw new CliError(`${flagName} must be a non-negative integer.`, {
|
|
3098
|
+
code: 'DATASET_MAINTENANCE_INTEGER_INVALID',
|
|
3099
|
+
exitCode: 2,
|
|
3100
|
+
details: { flag: flagName, value },
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
3103
|
+
return Number.parseInt(value.trim(), 10);
|
|
3104
|
+
}
|
|
3039
3105
|
function parseDatasetMaintenancePlanFlags(args) {
|
|
3040
3106
|
let values;
|
|
3041
3107
|
try {
|
|
@@ -3062,8 +3128,15 @@ function parseDatasetMaintenancePlanFlags(args) {
|
|
|
3062
3128
|
}
|
|
3063
3129
|
const rawOperation = typeof values.operation === 'string' ? values.operation : null;
|
|
3064
3130
|
if (rawOperation !== null &&
|
|
3065
|
-
![
|
|
3066
|
-
|
|
3131
|
+
![
|
|
3132
|
+
'delete',
|
|
3133
|
+
'retire',
|
|
3134
|
+
'redo-import',
|
|
3135
|
+
'repair-references',
|
|
3136
|
+
'merge-support-aliases',
|
|
3137
|
+
'rebuild-derivatives',
|
|
3138
|
+
].includes(rawOperation)) {
|
|
3139
|
+
throw new CliError("--operation must be 'delete', 'retire', 'redo-import', 'repair-references', 'merge-support-aliases', or 'rebuild-derivatives'.", {
|
|
3067
3140
|
code: 'DATASET_MAINTENANCE_OPERATION_INVALID',
|
|
3068
3141
|
exitCode: 2,
|
|
3069
3142
|
details: rawOperation,
|
|
@@ -3115,6 +3188,54 @@ function parseDatasetMaintenanceApplyFlags(args) {
|
|
|
3115
3188
|
dryRun: Boolean(values['dry-run']),
|
|
3116
3189
|
};
|
|
3117
3190
|
}
|
|
3191
|
+
function parseDatasetMaintenanceProtectedFlags(args) {
|
|
3192
|
+
let values;
|
|
3193
|
+
try {
|
|
3194
|
+
({ values } = parseArgs({
|
|
3195
|
+
args,
|
|
3196
|
+
allowPositionals: false,
|
|
3197
|
+
strict: true,
|
|
3198
|
+
options: {
|
|
3199
|
+
help: { type: 'boolean', short: 'h' },
|
|
3200
|
+
json: { type: 'boolean' },
|
|
3201
|
+
plan: { type: 'string' },
|
|
3202
|
+
freeze: { type: 'string' },
|
|
3203
|
+
approval: { type: 'string' },
|
|
3204
|
+
'out-dir': { type: 'string' },
|
|
3205
|
+
commit: { type: 'boolean' },
|
|
3206
|
+
'status-only': { type: 'boolean' },
|
|
3207
|
+
'approve-execution': { type: 'string' },
|
|
3208
|
+
confirm: { type: 'string' },
|
|
3209
|
+
'wait-seconds': { type: 'string' },
|
|
3210
|
+
'poll-ms': { type: 'string' },
|
|
3211
|
+
'page-size': { type: 'string' },
|
|
3212
|
+
'timeout-ms': { type: 'string' },
|
|
3213
|
+
},
|
|
3214
|
+
}));
|
|
3215
|
+
}
|
|
3216
|
+
catch (error) {
|
|
3217
|
+
throw new CliError(String(error), {
|
|
3218
|
+
code: 'INVALID_ARGS',
|
|
3219
|
+
exitCode: 2,
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
return {
|
|
3223
|
+
help: Boolean(values.help),
|
|
3224
|
+
json: Boolean(values.json),
|
|
3225
|
+
planPath: typeof values.plan === 'string' ? values.plan : '',
|
|
3226
|
+
freezePath: typeof values.freeze === 'string' ? values.freeze : '',
|
|
3227
|
+
approvalPath: typeof values.approval === 'string' ? values.approval : '',
|
|
3228
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
|
|
3229
|
+
commit: Boolean(values.commit),
|
|
3230
|
+
statusOnly: Boolean(values['status-only']),
|
|
3231
|
+
approveExecution: typeof values['approve-execution'] === 'string' ? values['approve-execution'] : undefined,
|
|
3232
|
+
confirm: typeof values.confirm === 'string' ? values.confirm : undefined,
|
|
3233
|
+
waitSeconds: parseDatasetMaintenanceNonNegativeInteger(values['wait-seconds'], '--wait-seconds'),
|
|
3234
|
+
pollMs: parseDatasetMaintenancePositiveInteger(values['poll-ms'], '--poll-ms'),
|
|
3235
|
+
pageSize: parseDatasetMaintenancePositiveInteger(values['page-size'], '--page-size'),
|
|
3236
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3118
3239
|
function parseDatasetMaintenanceVerifyFlags(args) {
|
|
3119
3240
|
let values;
|
|
3120
3241
|
try {
|
|
@@ -4894,6 +5015,7 @@ export async function executeCli(argv, deps) {
|
|
|
4894
5015
|
const datasetMaintenanceClearAccountImpl = deps.runDatasetMaintenanceClearAccountImpl ?? runDatasetMaintenanceClearAccount;
|
|
4895
5016
|
const datasetMaintenancePlanImpl = deps.runDatasetMaintenancePlanImpl ?? runDatasetMaintenancePlan;
|
|
4896
5017
|
const datasetMaintenanceApplyImpl = deps.runDatasetMaintenanceApplyImpl ?? runDatasetMaintenanceApply;
|
|
5018
|
+
const datasetMaintenanceProtectedImpl = deps.runDatasetMaintenanceProtectedImpl ?? runDatasetMaintenanceProtected;
|
|
4897
5019
|
const datasetMaintenanceVerifyImpl = deps.runDatasetMaintenanceVerifyImpl ?? runDatasetMaintenanceVerify;
|
|
4898
5020
|
const datasetSourceUploadAttachmentsImpl = deps.runDatasetSourceUploadAttachmentsImpl ?? runDatasetSourceUploadAttachments;
|
|
4899
5021
|
if (flags.version) {
|
|
@@ -5606,6 +5728,85 @@ export async function executeCli(argv, deps) {
|
|
|
5606
5728
|
stderr: '',
|
|
5607
5729
|
};
|
|
5608
5730
|
}
|
|
5731
|
+
if (action === 'run-protected') {
|
|
5732
|
+
const datasetFlags = parseDatasetMaintenanceProtectedFlags(commandArgs.slice(1));
|
|
5733
|
+
if (datasetFlags.help) {
|
|
5734
|
+
return {
|
|
5735
|
+
exitCode: 0,
|
|
5736
|
+
stdout: `${renderDatasetMaintenanceRunProtectedHelp()}\n`,
|
|
5737
|
+
stderr: '',
|
|
5738
|
+
};
|
|
5739
|
+
}
|
|
5740
|
+
if (!datasetFlags.planPath) {
|
|
5741
|
+
throw new CliError('dataset maintenance run-protected requires --plan.', {
|
|
5742
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_PLAN_REQUIRED',
|
|
5743
|
+
exitCode: 2,
|
|
5744
|
+
});
|
|
5745
|
+
}
|
|
5746
|
+
if (!datasetFlags.freezePath) {
|
|
5747
|
+
throw new CliError('dataset maintenance run-protected requires --freeze.', {
|
|
5748
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_FREEZE_REQUIRED',
|
|
5749
|
+
exitCode: 2,
|
|
5750
|
+
});
|
|
5751
|
+
}
|
|
5752
|
+
if (!datasetFlags.approvalPath) {
|
|
5753
|
+
throw new CliError('dataset maintenance run-protected requires --approval.', {
|
|
5754
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVAL_FILE_REQUIRED',
|
|
5755
|
+
exitCode: 2,
|
|
5756
|
+
});
|
|
5757
|
+
}
|
|
5758
|
+
if (!datasetFlags.outDir) {
|
|
5759
|
+
throw new CliError('dataset maintenance run-protected requires --out-dir.', {
|
|
5760
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_OUT_DIR_REQUIRED',
|
|
5761
|
+
exitCode: 2,
|
|
5762
|
+
});
|
|
5763
|
+
}
|
|
5764
|
+
if (datasetFlags.commit && datasetFlags.statusOnly) {
|
|
5765
|
+
throw new CliError('Cannot pass both --commit and --status-only.', {
|
|
5766
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_MODE_CONFLICT',
|
|
5767
|
+
exitCode: 2,
|
|
5768
|
+
});
|
|
5769
|
+
}
|
|
5770
|
+
if (!datasetFlags.commit && !datasetFlags.statusOnly) {
|
|
5771
|
+
throw new CliError('dataset maintenance run-protected requires either --commit or --status-only.', {
|
|
5772
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_MODE_REQUIRED',
|
|
5773
|
+
exitCode: 2,
|
|
5774
|
+
});
|
|
5775
|
+
}
|
|
5776
|
+
if (datasetFlags.commit && !datasetFlags.approveExecution) {
|
|
5777
|
+
throw new CliError('dataset maintenance run-protected requires --approve-execution <sha256> with --commit.', {
|
|
5778
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_APPROVAL_REQUIRED',
|
|
5779
|
+
exitCode: 2,
|
|
5780
|
+
});
|
|
5781
|
+
}
|
|
5782
|
+
if (datasetFlags.commit && !datasetFlags.confirm) {
|
|
5783
|
+
throw new CliError('dataset maintenance run-protected requires --confirm <email> with --commit.', {
|
|
5784
|
+
code: 'DATASET_MAINTENANCE_PROTECTED_CONFIRM_REQUIRED',
|
|
5785
|
+
exitCode: 2,
|
|
5786
|
+
});
|
|
5787
|
+
}
|
|
5788
|
+
const report = await datasetMaintenanceProtectedImpl({
|
|
5789
|
+
planPath: datasetFlags.planPath,
|
|
5790
|
+
freezePath: datasetFlags.freezePath,
|
|
5791
|
+
approvalPath: datasetFlags.approvalPath,
|
|
5792
|
+
outDir: datasetFlags.outDir,
|
|
5793
|
+
commit: datasetFlags.commit,
|
|
5794
|
+
statusOnly: datasetFlags.statusOnly,
|
|
5795
|
+
approveExecution: datasetFlags.approveExecution,
|
|
5796
|
+
confirm: datasetFlags.confirm,
|
|
5797
|
+
waitSeconds: datasetFlags.waitSeconds,
|
|
5798
|
+
pollMs: datasetFlags.pollMs,
|
|
5799
|
+
pageSize: datasetFlags.pageSize,
|
|
5800
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
5801
|
+
env: deps.env,
|
|
5802
|
+
fetchImpl: deps.fetchImpl,
|
|
5803
|
+
});
|
|
5804
|
+
return {
|
|
5805
|
+
exitCode: report.status === 'passed' ? 0 : 1,
|
|
5806
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
5807
|
+
stderr: '',
|
|
5808
|
+
};
|
|
5809
|
+
}
|
|
5609
5810
|
if (action === 'verify') {
|
|
5610
5811
|
const datasetFlags = parseDatasetMaintenanceVerifyFlags(commandArgs.slice(1));
|
|
5611
5812
|
if (datasetFlags.help) {
|
|
@@ -5630,12 +5831,12 @@ export async function executeCli(argv, deps) {
|
|
|
5630
5831
|
fetchImpl: deps.fetchImpl,
|
|
5631
5832
|
});
|
|
5632
5833
|
return {
|
|
5633
|
-
exitCode: report.status === '
|
|
5834
|
+
exitCode: report.status === 'passed' ? 0 : 1,
|
|
5634
5835
|
stdout: stringifyJson(report, datasetFlags.json),
|
|
5635
5836
|
stderr: '',
|
|
5636
5837
|
};
|
|
5637
5838
|
}
|
|
5638
|
-
throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', or 'verify'.", {
|
|
5839
|
+
throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', 'run-protected', or 'verify'.", {
|
|
5639
5840
|
code: 'DATASET_MAINTENANCE_ACTION_INVALID',
|
|
5640
5841
|
exitCode: 2,
|
|
5641
5842
|
});
|