tracegrove 0.0.0-stage → 0.3.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/LICENSE +202 -0
- package/README.md +588 -2
- package/conformance/coordination-vectors.json +377 -0
- package/dist/adapters/browser/capabilities.d.ts +45 -0
- package/dist/adapters/browser/capabilities.js +14 -0
- package/dist/adapters/browser/capabilities.js.map +1 -0
- package/dist/adapters/browser/driver.d.ts +45 -0
- package/dist/adapters/browser/driver.js +295 -0
- package/dist/adapters/browser/driver.js.map +1 -0
- package/dist/adapters/browser/session.d.ts +21 -0
- package/dist/adapters/browser/session.js +87 -0
- package/dist/adapters/browser/session.js.map +1 -0
- package/dist/adapters/http/capabilities.d.ts +2 -0
- package/dist/adapters/http/capabilities.js +21 -0
- package/dist/adapters/http/capabilities.js.map +1 -0
- package/dist/adapters/http/driver.d.ts +55 -0
- package/dist/adapters/http/driver.js +125 -0
- package/dist/adapters/http/driver.js.map +1 -0
- package/dist/adapters/job/capabilities.d.ts +45 -0
- package/dist/adapters/job/capabilities.js +8 -0
- package/dist/adapters/job/capabilities.js.map +1 -0
- package/dist/adapters/job/driver.d.ts +26 -0
- package/dist/adapters/job/driver.js +110 -0
- package/dist/adapters/job/driver.js.map +1 -0
- package/dist/adapters/job/types.d.ts +9 -0
- package/dist/adapters/job/types.js +2 -0
- package/dist/adapters/job/types.js.map +1 -0
- package/dist/adapters/mcp/capabilities.d.ts +46 -0
- package/dist/adapters/mcp/capabilities.js +17 -0
- package/dist/adapters/mcp/capabilities.js.map +1 -0
- package/dist/adapters/mcp/driver.d.ts +10 -0
- package/dist/adapters/mcp/driver.js +83 -0
- package/dist/adapters/mcp/driver.js.map +1 -0
- package/dist/adapters/poll.d.ts +12 -0
- package/dist/adapters/poll.js +31 -0
- package/dist/adapters/poll.js.map +1 -0
- package/dist/authoring/activity.d.ts +17 -0
- package/dist/authoring/activity.js +18 -0
- package/dist/authoring/activity.js.map +1 -0
- package/dist/authoring/agent.d.ts +70 -0
- package/dist/authoring/agent.js +268 -0
- package/dist/authoring/agent.js.map +1 -0
- package/dist/authoring/appLaunch.d.ts +7 -0
- package/dist/authoring/appLaunch.js +32 -0
- package/dist/authoring/appLaunch.js.map +1 -0
- package/dist/authoring/appLocation.d.ts +2 -0
- package/dist/authoring/appLocation.js +5 -0
- package/dist/authoring/appLocation.js.map +1 -0
- package/dist/authoring/browser.d.ts +15 -0
- package/dist/authoring/browser.js +20 -0
- package/dist/authoring/browser.js.map +1 -0
- package/dist/authoring/compile.d.ts +47 -0
- package/dist/authoring/compile.js +508 -0
- package/dist/authoring/compile.js.map +1 -0
- package/dist/authoring/discover.d.ts +43 -0
- package/dist/authoring/discover.js +149 -0
- package/dist/authoring/discover.js.map +1 -0
- package/dist/authoring/environmentTemplates.d.ts +3 -0
- package/dist/authoring/environmentTemplates.js +24 -0
- package/dist/authoring/environmentTemplates.js.map +1 -0
- package/dist/authoring/heal.d.ts +108 -0
- package/dist/authoring/heal.js +723 -0
- package/dist/authoring/heal.js.map +1 -0
- package/dist/authoring/index.d.ts +14 -0
- package/dist/authoring/index.js +15 -0
- package/dist/authoring/index.js.map +1 -0
- package/dist/authoring/init.d.ts +21 -0
- package/dist/authoring/init.js +141 -0
- package/dist/authoring/init.js.map +1 -0
- package/dist/authoring/localSettings.d.ts +33 -0
- package/dist/authoring/localSettings.js +31 -0
- package/dist/authoring/localSettings.js.map +1 -0
- package/dist/authoring/media.d.ts +10 -0
- package/dist/authoring/media.js +37 -0
- package/dist/authoring/media.js.map +1 -0
- package/dist/authoring/module.d.ts +2 -0
- package/dist/authoring/module.js +38 -0
- package/dist/authoring/module.js.map +1 -0
- package/dist/authoring/run.d.ts +74 -0
- package/dist/authoring/run.js +242 -0
- package/dist/authoring/run.js.map +1 -0
- package/dist/authoring/runSource.d.ts +6 -0
- package/dist/authoring/runSource.js +24 -0
- package/dist/authoring/runSource.js.map +1 -0
- package/dist/authoring/savedRun.d.ts +13 -0
- package/dist/authoring/savedRun.js +94 -0
- package/dist/authoring/savedRun.js.map +1 -0
- package/dist/authoring/schema.d.ts +574 -0
- package/dist/authoring/schema.js +147 -0
- package/dist/authoring/schema.js.map +1 -0
- package/dist/authoring/snapshotSource.d.ts +13 -0
- package/dist/authoring/snapshotSource.js +41 -0
- package/dist/authoring/snapshotSource.js.map +1 -0
- package/dist/authoring/sourceSelection.d.ts +34 -0
- package/dist/authoring/sourceSelection.js +13 -0
- package/dist/authoring/sourceSelection.js.map +1 -0
- package/dist/authoring/sources.d.ts +5 -0
- package/dist/authoring/sources.js +65 -0
- package/dist/authoring/sources.js.map +1 -0
- package/dist/authoring/status.d.ts +48 -0
- package/dist/authoring/status.js +100 -0
- package/dist/authoring/status.js.map +1 -0
- package/dist/authoring/typed.d.ts +6 -0
- package/dist/authoring/typed.js +5 -0
- package/dist/authoring/typed.js.map +1 -0
- package/dist/authoring/ui.d.ts +10 -0
- package/dist/authoring/ui.js +486 -0
- package/dist/authoring/ui.js.map +1 -0
- package/dist/authoring/uiPage.d.ts +1 -0
- package/dist/authoring/uiPage.js +358 -0
- package/dist/authoring/uiPage.js.map +1 -0
- package/dist/authoring/uiSourceControls.d.ts +2 -0
- package/dist/authoring/uiSourceControls.js +41 -0
- package/dist/authoring/uiSourceControls.js.map +1 -0
- package/dist/authoring/verificationSource.d.ts +41 -0
- package/dist/authoring/verificationSource.js +46 -0
- package/dist/authoring/verificationSource.js.map +1 -0
- package/dist/authoring/workspace.d.ts +33 -0
- package/dist/authoring/workspace.js +58 -0
- package/dist/authoring/workspace.js.map +1 -0
- package/dist/cli/arguments.d.ts +288 -0
- package/dist/cli/arguments.js +121 -0
- package/dist/cli/arguments.js.map +1 -0
- package/dist/cli/cleanup.d.ts +18 -0
- package/dist/cli/cleanup.js +40 -0
- package/dist/cli/cleanup.js.map +1 -0
- package/dist/cli/doctor.d.ts +51 -0
- package/dist/cli/doctor.js +118 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/errors.d.ts +2 -0
- package/dist/cli/errors.js +84 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/jsonFile.d.ts +2 -0
- package/dist/cli/jsonFile.js +15 -0
- package/dist/cli/jsonFile.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +603 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/render.d.ts +22 -0
- package/dist/cli/render.js +150 -0
- package/dist/cli/render.js.map +1 -0
- package/dist/cli/samples/catalog.d.ts +10 -0
- package/dist/cli/samples/catalog.js +3 -0
- package/dist/cli/samples/catalog.js.map +1 -0
- package/dist/cli/samples/write.d.ts +5 -0
- package/dist/cli/samples/write.js +64 -0
- package/dist/cli/samples/write.js.map +1 -0
- package/dist/cli/source.d.ts +41 -0
- package/dist/cli/source.js +59 -0
- package/dist/cli/source.js.map +1 -0
- package/dist/core/activationDecision.d.ts +153 -0
- package/dist/core/activationDecision.js +34 -0
- package/dist/core/activationDecision.js.map +1 -0
- package/dist/core/artifacts.d.ts +18 -0
- package/dist/core/artifacts.js +79 -0
- package/dist/core/artifacts.js.map +1 -0
- package/dist/core/atomicFiles.d.ts +9 -0
- package/dist/core/atomicFiles.js +76 -0
- package/dist/core/atomicFiles.js.map +1 -0
- package/dist/core/boundedFile.d.ts +2 -0
- package/dist/core/boundedFile.js +28 -0
- package/dist/core/boundedFile.js.map +1 -0
- package/dist/core/bundle.d.ts +77 -0
- package/dist/core/bundle.js +375 -0
- package/dist/core/bundle.js.map +1 -0
- package/dist/core/bundleArchive.d.ts +10 -0
- package/dist/core/bundleArchive.js +47 -0
- package/dist/core/bundleArchive.js.map +1 -0
- package/dist/core/bundleEvidence.d.ts +12 -0
- package/dist/core/bundleEvidence.js +169 -0
- package/dist/core/bundleEvidence.js.map +1 -0
- package/dist/core/bundleExport.d.ts +12 -0
- package/dist/core/bundleExport.js +36 -0
- package/dist/core/bundleExport.js.map +1 -0
- package/dist/core/bundleFiles.d.ts +5 -0
- package/dist/core/bundleFiles.js +47 -0
- package/dist/core/bundleFiles.js.map +1 -0
- package/dist/core/bundlePaths.d.ts +2 -0
- package/dist/core/bundlePaths.js +7 -0
- package/dist/core/bundlePaths.js.map +1 -0
- package/dist/core/bundleSnapshot.d.ts +26 -0
- package/dist/core/bundleSnapshot.js +71 -0
- package/dist/core/bundleSnapshot.js.map +1 -0
- package/dist/core/capabilityBoundary.d.ts +1452 -0
- package/dist/core/capabilityBoundary.js +361 -0
- package/dist/core/capabilityBoundary.js.map +1 -0
- package/dist/core/capabilityLifecycle.d.ts +366 -0
- package/dist/core/capabilityLifecycle.js +79 -0
- package/dist/core/capabilityLifecycle.js.map +1 -0
- package/dist/core/cleanup.d.ts +35 -0
- package/dist/core/cleanup.js +71 -0
- package/dist/core/cleanup.js.map +1 -0
- package/dist/core/cleanupActions.d.ts +5 -0
- package/dist/core/cleanupActions.js +15 -0
- package/dist/core/cleanupActions.js.map +1 -0
- package/dist/core/cleanupAttestation.d.ts +23 -0
- package/dist/core/cleanupAttestation.js +57 -0
- package/dist/core/cleanupAttestation.js.map +1 -0
- package/dist/core/clock.d.ts +4 -0
- package/dist/core/clock.js +14 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/compiler.d.ts +19 -0
- package/dist/core/compiler.js +200 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/controller.d.ts +7 -0
- package/dist/core/controller.js +132 -0
- package/dist/core/controller.js.map +1 -0
- package/dist/core/coordination.d.ts +72 -0
- package/dist/core/coordination.js +118 -0
- package/dist/core/coordination.js.map +1 -0
- package/dist/core/corpus.d.ts +60 -0
- package/dist/core/corpus.js +216 -0
- package/dist/core/corpus.js.map +1 -0
- package/dist/core/deadline.d.ts +12 -0
- package/dist/core/deadline.js +38 -0
- package/dist/core/deadline.js.map +1 -0
- package/dist/core/deliveryJournal.d.ts +37 -0
- package/dist/core/deliveryJournal.js +85 -0
- package/dist/core/deliveryJournal.js.map +1 -0
- package/dist/core/environmentPreflight.d.ts +14 -0
- package/dist/core/environmentPreflight.js +179 -0
- package/dist/core/environmentPreflight.js.map +1 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +29 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/events.d.ts +14 -0
- package/dist/core/events.js +37 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/executionInspection.d.ts +90 -0
- package/dist/core/executionInspection.js +31 -0
- package/dist/core/executionInspection.js.map +1 -0
- package/dist/core/executionOwnership.d.ts +72 -0
- package/dist/core/executionOwnership.js +82 -0
- package/dist/core/executionOwnership.js.map +1 -0
- package/dist/core/executionPreparation.d.ts +362 -0
- package/dist/core/executionPreparation.js +93 -0
- package/dist/core/executionPreparation.js.map +1 -0
- package/dist/core/executionReadback.d.ts +15 -0
- package/dist/core/executionReadback.js +21 -0
- package/dist/core/executionReadback.js.map +1 -0
- package/dist/core/executor.d.ts +46 -0
- package/dist/core/executor.js +616 -0
- package/dist/core/executor.js.map +1 -0
- package/dist/core/frozenBundle.d.ts +314 -0
- package/dist/core/frozenBundle.js +24 -0
- package/dist/core/frozenBundle.js.map +1 -0
- package/dist/core/fsDurability.d.ts +2 -0
- package/dist/core/fsDurability.js +12 -0
- package/dist/core/fsDurability.js.map +1 -0
- package/dist/core/generators.d.ts +4 -0
- package/dist/core/generators.js +71 -0
- package/dist/core/generators.js.map +1 -0
- package/dist/core/gitSnapshot.d.ts +63 -0
- package/dist/core/gitSnapshot.js +55 -0
- package/dist/core/gitSnapshot.js.map +1 -0
- package/dist/core/gitSources.d.ts +29 -0
- package/dist/core/gitSources.js +97 -0
- package/dist/core/gitSources.js.map +1 -0
- package/dist/core/ledger.d.ts +38 -0
- package/dist/core/ledger.js +169 -0
- package/dist/core/ledger.js.map +1 -0
- package/dist/core/ledgerInspection.d.ts +18 -0
- package/dist/core/ledgerInspection.js +66 -0
- package/dist/core/ledgerInspection.js.map +1 -0
- package/dist/core/ledgerRecords.d.ts +23 -0
- package/dist/core/ledgerRecords.js +29 -0
- package/dist/core/ledgerRecords.js.map +1 -0
- package/dist/core/localActivationState.d.ts +260 -0
- package/dist/core/localActivationState.js +49 -0
- package/dist/core/localActivationState.js.map +1 -0
- package/dist/core/localPromotionState.d.ts +387 -0
- package/dist/core/localPromotionState.js +22 -0
- package/dist/core/localPromotionState.js.map +1 -0
- package/dist/core/localQualificationResults.d.ts +39 -0
- package/dist/core/localQualificationResults.js +160 -0
- package/dist/core/localQualificationResults.js.map +1 -0
- package/dist/core/localReviewStore.d.ts +28 -0
- package/dist/core/localReviewStore.js +167 -0
- package/dist/core/localReviewStore.js.map +1 -0
- package/dist/core/localScenarioActivation.d.ts +6 -0
- package/dist/core/localScenarioActivation.js +70 -0
- package/dist/core/localScenarioActivation.js.map +1 -0
- package/dist/core/localScenarioOwner.d.ts +20 -0
- package/dist/core/localScenarioOwner.js +2 -0
- package/dist/core/localScenarioOwner.js.map +1 -0
- package/dist/core/localScenarioPromotion.d.ts +9 -0
- package/dist/core/localScenarioPromotion.js +49 -0
- package/dist/core/localScenarioPromotion.js.map +1 -0
- package/dist/core/localScenarioState.d.ts +2297 -0
- package/dist/core/localScenarioState.js +117 -0
- package/dist/core/localScenarioState.js.map +1 -0
- package/dist/core/localScenarioStore.d.ts +838 -0
- package/dist/core/localScenarioStore.js +218 -0
- package/dist/core/localScenarioStore.js.map +1 -0
- package/dist/core/localScenarioStructure.d.ts +4 -0
- package/dist/core/localScenarioStructure.js +52 -0
- package/dist/core/localScenarioStructure.js.map +1 -0
- package/dist/core/localStructureState.d.ts +2 -0
- package/dist/core/localStructureState.js +22 -0
- package/dist/core/localStructureState.js.map +1 -0
- package/dist/core/lookup.d.ts +662 -0
- package/dist/core/lookup.js +55 -0
- package/dist/core/lookup.js.map +1 -0
- package/dist/core/ownership.d.ts +3 -0
- package/dist/core/ownership.js +24 -0
- package/dist/core/ownership.js.map +1 -0
- package/dist/core/planInspection.d.ts +108 -0
- package/dist/core/planInspection.js +44 -0
- package/dist/core/planInspection.js.map +1 -0
- package/dist/core/planner.d.ts +14 -0
- package/dist/core/planner.js +261 -0
- package/dist/core/planner.js.map +1 -0
- package/dist/core/qualification.d.ts +26 -0
- package/dist/core/qualification.js +58 -0
- package/dist/core/qualification.js.map +1 -0
- package/dist/core/qualificationBundle.d.ts +6 -0
- package/dist/core/qualificationBundle.js +51 -0
- package/dist/core/qualificationBundle.js.map +1 -0
- package/dist/core/qualificationExecution.d.ts +879 -0
- package/dist/core/qualificationExecution.js +54 -0
- package/dist/core/qualificationExecution.js.map +1 -0
- package/dist/core/recoveryStatus.d.ts +6 -0
- package/dist/core/recoveryStatus.js +123 -0
- package/dist/core/recoveryStatus.js.map +1 -0
- package/dist/core/reducer.d.ts +56 -0
- package/dist/core/reducer.js +355 -0
- package/dist/core/reducer.js.map +1 -0
- package/dist/core/replayAssessment.d.ts +15 -0
- package/dist/core/replayAssessment.js +78 -0
- package/dist/core/replayAssessment.js.map +1 -0
- package/dist/core/replayEvidence.d.ts +7 -0
- package/dist/core/replayEvidence.js +58 -0
- package/dist/core/replayEvidence.js.map +1 -0
- package/dist/core/repositorySelectionEvidence.d.ts +3 -0
- package/dist/core/repositorySelectionEvidence.js +58 -0
- package/dist/core/repositorySelectionEvidence.js.map +1 -0
- package/dist/core/rerun.d.ts +3 -0
- package/dist/core/rerun.js +24 -0
- package/dist/core/rerun.js.map +1 -0
- package/dist/core/resultSink.d.ts +52 -0
- package/dist/core/resultSink.js +120 -0
- package/dist/core/resultSink.js.map +1 -0
- package/dist/core/review.d.ts +22 -0
- package/dist/core/review.js +65 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/runnerCapabilities.d.ts +22 -0
- package/dist/core/runnerCapabilities.js +44 -0
- package/dist/core/runnerCapabilities.js.map +1 -0
- package/dist/core/scenario.d.ts +32 -0
- package/dist/core/scenario.js +119 -0
- package/dist/core/scenario.js.map +1 -0
- package/dist/core/scenarioActivation.d.ts +16 -0
- package/dist/core/scenarioActivation.js +47 -0
- package/dist/core/scenarioActivation.js.map +1 -0
- package/dist/core/scenarioStructure.d.ts +400 -0
- package/dist/core/scenarioStructure.js +72 -0
- package/dist/core/scenarioStructure.js.map +1 -0
- package/dist/core/snapshotEvidence.d.ts +3 -0
- package/dist/core/snapshotEvidence.js +37 -0
- package/dist/core/snapshotEvidence.js.map +1 -0
- package/dist/core/snapshotRepository.d.ts +48 -0
- package/dist/core/snapshotRepository.js +47 -0
- package/dist/core/snapshotRepository.js.map +1 -0
- package/dist/core/source-analysis.d.ts +18 -0
- package/dist/core/source-analysis.js +99 -0
- package/dist/core/source-analysis.js.map +1 -0
- package/dist/core/source-citation.d.ts +53 -0
- package/dist/core/source-citation.js +59 -0
- package/dist/core/source-citation.js.map +1 -0
- package/dist/core/sourcePromotion.d.ts +929 -0
- package/dist/core/sourcePromotion.js +92 -0
- package/dist/core/sourcePromotion.js.map +1 -0
- package/dist/core/sourceReviewEvidence.d.ts +271 -0
- package/dist/core/sourceReviewEvidence.js +24 -0
- package/dist/core/sourceReviewEvidence.js.map +1 -0
- package/dist/core/targetObservation.d.ts +3 -0
- package/dist/core/targetObservation.js +26 -0
- package/dist/core/targetObservation.js.map +1 -0
- package/dist/hosts/launchTemplates.d.ts +2 -0
- package/dist/hosts/launchTemplates.js +5 -0
- package/dist/hosts/launchTemplates.js.map +1 -0
- package/dist/hosts/local.d.ts +17 -0
- package/dist/hosts/local.js +311 -0
- package/dist/hosts/local.js.map +1 -0
- package/dist/hosts/localSupervisor.d.ts +1 -0
- package/dist/hosts/localSupervisor.js +115 -0
- package/dist/hosts/localSupervisor.js.map +1 -0
- package/dist/hosts/mock.d.ts +4 -0
- package/dist/hosts/mock.js +82 -0
- package/dist/hosts/mock.js.map +1 -0
- package/dist/hosts/pinnedArguments.d.ts +3 -0
- package/dist/hosts/pinnedArguments.js +39 -0
- package/dist/hosts/pinnedArguments.js.map +1 -0
- package/dist/hosts/runtime.d.ts +5 -0
- package/dist/hosts/runtime.js +60 -0
- package/dist/hosts/runtime.js.map +1 -0
- package/dist/hosts/sourceIdentity.d.ts +54 -0
- package/dist/hosts/sourceIdentity.js +27 -0
- package/dist/hosts/sourceIdentity.js.map +1 -0
- package/dist/hosts/types.d.ts +39 -0
- package/dist/hosts/types.js +2 -0
- package/dist/hosts/types.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/awr/attachment.d.ts +34 -0
- package/dist/integrations/awr/attachment.js +120 -0
- package/dist/integrations/awr/attachment.js.map +1 -0
- package/dist/integrations/awr/attachmentContracts.d.ts +273 -0
- package/dist/integrations/awr/attachmentContracts.js +39 -0
- package/dist/integrations/awr/attachmentContracts.js.map +1 -0
- package/dist/integrations/awr/attachmentHttp.d.ts +9 -0
- package/dist/integrations/awr/attachmentHttp.js +19 -0
- package/dist/integrations/awr/attachmentHttp.js.map +1 -0
- package/dist/integrations/awr/cli.d.ts +7 -0
- package/dist/integrations/awr/cli.js +43 -0
- package/dist/integrations/awr/cli.js.map +1 -0
- package/dist/integrations/awr/contracts.d.ts +54 -0
- package/dist/integrations/awr/contracts.js +33 -0
- package/dist/integrations/awr/contracts.js.map +1 -0
- package/dist/integrations/awr/http.d.ts +8 -0
- package/dist/integrations/awr/http.js +23 -0
- package/dist/integrations/awr/http.js.map +1 -0
- package/dist/integrations/awr/index.d.ts +7 -0
- package/dist/integrations/awr/index.js +8 -0
- package/dist/integrations/awr/index.js.map +1 -0
- package/dist/integrations/awr/jsonHttp.d.ts +15 -0
- package/dist/integrations/awr/jsonHttp.js +69 -0
- package/dist/integrations/awr/jsonHttp.js.map +1 -0
- package/dist/integrations/awr/outbox.d.ts +28 -0
- package/dist/integrations/awr/outbox.js +88 -0
- package/dist/integrations/awr/outbox.js.map +1 -0
- package/dist/integrations/awr/projection.d.ts +4 -0
- package/dist/integrations/awr/projection.js +54 -0
- package/dist/integrations/awr/projection.js.map +1 -0
- package/dist/protocol/canonical.d.ts +41 -0
- package/dist/protocol/canonical.js +114 -0
- package/dist/protocol/canonical.js.map +1 -0
- package/dist/protocol/index.d.ts +9620 -0
- package/dist/protocol/index.js +185 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/primitives.d.ts +63 -0
- package/dist/protocol/primitives.js +46 -0
- package/dist/protocol/primitives.js.map +1 -0
- package/dist/protocol/schemas/browser.d.ts +153 -0
- package/dist/protocol/schemas/browser.js +29 -0
- package/dist/protocol/schemas/browser.js.map +1 -0
- package/dist/protocol/schemas/capability.d.ts +2126 -0
- package/dist/protocol/schemas/capability.js +165 -0
- package/dist/protocol/schemas/capability.js.map +1 -0
- package/dist/protocol/schemas/capabilityLifecycle.d.ts +509 -0
- package/dist/protocol/schemas/capabilityLifecycle.js +47 -0
- package/dist/protocol/schemas/capabilityLifecycle.js.map +1 -0
- package/dist/protocol/schemas/cleanup.d.ts +109 -0
- package/dist/protocol/schemas/cleanup.js +59 -0
- package/dist/protocol/schemas/cleanup.js.map +1 -0
- package/dist/protocol/schemas/cli.d.ts +121 -0
- package/dist/protocol/schemas/cli.js +24 -0
- package/dist/protocol/schemas/cli.js.map +1 -0
- package/dist/protocol/schemas/config.d.ts +59 -0
- package/dist/protocol/schemas/config.js +32 -0
- package/dist/protocol/schemas/config.js.map +1 -0
- package/dist/protocol/schemas/corpus.d.ts +36 -0
- package/dist/protocol/schemas/corpus.js +10 -0
- package/dist/protocol/schemas/corpus.js.map +1 -0
- package/dist/protocol/schemas/definitions.d.ts +3409 -0
- package/dist/protocol/schemas/definitions.js +431 -0
- package/dist/protocol/schemas/definitions.js.map +1 -0
- package/dist/protocol/schemas/evidenceProjection.d.ts +146 -0
- package/dist/protocol/schemas/evidenceProjection.js +18 -0
- package/dist/protocol/schemas/evidenceProjection.js.map +1 -0
- package/dist/protocol/schemas/execution.d.ts +3179 -0
- package/dist/protocol/schemas/execution.js +500 -0
- package/dist/protocol/schemas/execution.js.map +1 -0
- package/dist/protocol/schemas/gitSources.d.ts +330 -0
- package/dist/protocol/schemas/gitSources.js +32 -0
- package/dist/protocol/schemas/gitSources.js.map +1 -0
- package/dist/protocol/schemas/mcp.d.ts +24 -0
- package/dist/protocol/schemas/mcp.js +16 -0
- package/dist/protocol/schemas/mcp.js.map +1 -0
- package/dist/protocol/schemas/nativeJob.d.ts +106 -0
- package/dist/protocol/schemas/nativeJob.js +16 -0
- package/dist/protocol/schemas/nativeJob.js.map +1 -0
- package/dist/protocol/schemas/portableEnvironment.d.ts +1256 -0
- package/dist/protocol/schemas/portableEnvironment.js +108 -0
- package/dist/protocol/schemas/portableEnvironment.js.map +1 -0
- package/dist/protocol/schemas/promotion.d.ts +132 -0
- package/dist/protocol/schemas/promotion.js +9 -0
- package/dist/protocol/schemas/promotion.js.map +1 -0
- package/dist/protocol/schemas/protocol.d.ts +146 -0
- package/dist/protocol/schemas/protocol.js +25 -0
- package/dist/protocol/schemas/protocol.js.map +1 -0
- package/dist/protocol/schemas/recoveryStatus.d.ts +88 -0
- package/dist/protocol/schemas/recoveryStatus.js +20 -0
- package/dist/protocol/schemas/recoveryStatus.js.map +1 -0
- package/dist/protocol/schemas/resultSink.d.ts +80 -0
- package/dist/protocol/schemas/resultSink.js +14 -0
- package/dist/protocol/schemas/resultSink.js.map +1 -0
- package/dist/protocol/schemas/review.d.ts +248 -0
- package/dist/protocol/schemas/review.js +45 -0
- package/dist/protocol/schemas/review.js.map +1 -0
- package/dist/protocol/schemas/scenario.d.ts +810 -0
- package/dist/protocol/schemas/scenario.js +53 -0
- package/dist/protocol/schemas/scenario.js.map +1 -0
- package/dist/protocol/schemas/source.d.ts +300 -0
- package/dist/protocol/schemas/source.js +25 -0
- package/dist/protocol/schemas/source.js.map +1 -0
- package/dist/source/git.d.ts +36 -0
- package/dist/source/git.js +159 -0
- package/dist/source/git.js.map +1 -0
- package/dist/source/gitObjectProof.d.ts +12 -0
- package/dist/source/gitObjectProof.js +115 -0
- package/dist/source/gitObjectProof.js.map +1 -0
- package/dist/source/snapshotPaths.d.ts +2 -0
- package/dist/source/snapshotPaths.js +24 -0
- package/dist/source/snapshotPaths.js.map +1 -0
- package/dist/source/snapshotTree.d.ts +15 -0
- package/dist/source/snapshotTree.js +79 -0
- package/dist/source/snapshotTree.js.map +1 -0
- package/docs/architecture.md +126 -0
- package/docs/awr-delivery.md +102 -0
- package/docs/browser-driver.md +148 -0
- package/docs/cleanup-followups.md +74 -0
- package/docs/developer-ux.md +315 -0
- package/docs/examples/portable-environments/alongside_runner.json +199 -0
- package/docs/examples/portable-environments/external_staging.json +183 -0
- package/docs/git-object-proof.md +100 -0
- package/docs/git-source-resolution.md +133 -0
- package/docs/images/ui-run.png +0 -0
- package/docs/local-execution-recovery.md +55 -0
- package/docs/local-review-store.md +13 -0
- package/docs/local-scenario-store.md +91 -0
- package/docs/mcp-driver.md +87 -0
- package/docs/native-jobs.md +96 -0
- package/docs/portable-environments.md +155 -0
- package/docs/qualification-registration.md +58 -0
- package/docs/qualification-results.md +59 -0
- package/docs/replay-assessment.md +17 -0
- package/docs/result-sink.md +87 -0
- package/docs/scenario-activation.md +54 -0
- package/docs/scenario-structure.md +58 -0
- package/docs/source-promotion.md +104 -0
- package/docs/source-review.md +21 -0
- package/docs/verified-bundles.md +175 -0
- package/docs/work-report-attachment.md +127 -0
- package/package.json +45 -4
- package/samples/django-notes/manage.py +8 -0
- package/samples/django-notes/notes/__init__.py +0 -0
- package/samples/django-notes/notes/auth.py +14 -0
- package/samples/django-notes/notes/migrations/0001_initial.py +19 -0
- package/samples/django-notes/notes/migrations/__init__.py +0 -0
- package/samples/django-notes/notes/models.py +13 -0
- package/samples/django-notes/notes/views.py +33 -0
- package/samples/django-notes/notesite/__init__.py +0 -0
- package/samples/django-notes/notesite/settings.py +17 -0
- package/samples/django-notes/notesite/urls.py +9 -0
- package/samples/django-notes/requirements.txt +1 -0
- package/samples/django-notes/tracegrove/notes/crud.flow.yaml +27 -0
- package/samples/django-notes/tracegrove.config.yaml +7 -0
- package/samples/fastapi-notes/app/__init__.py +0 -0
- package/samples/fastapi-notes/app/main.py +69 -0
- package/samples/fastapi-notes/requirements.txt +2 -0
- package/samples/fastapi-notes/tracegrove/notes/crud.flow.yaml +27 -0
- package/samples/fastapi-notes/tracegrove.config.yaml +8 -0
- package/samples/notes-api/app/app.mjs +67 -0
- package/samples/notes-api/app/http.mjs +16 -0
- package/samples/notes-api/tracegrove/fixtures/existing-note.fixture.yaml +12 -0
- package/samples/notes-api/tracegrove/notes/create-read-delete.flow.yaml +35 -0
- package/samples/notes-api/tracegrove/notes/list.flow.yaml +25 -0
- package/samples/notes-api/tracegrove.config.yaml +15 -0
- package/samples/notes-api/verification/actions/notes.registry.yaml +6 -0
- package/samples/notes-api/verification/auth/host-issued-owner.yaml +6 -0
- package/samples/notes-api/verification/cases/notes.contract.yaml +51 -0
- package/samples/notes-api/verification/cases/notes.create.yaml +123 -0
- package/samples/notes-api/verification/cases/notes.suite.yaml +5 -0
- package/samples/notes-api/verification/components/notes-api-stub.profile.yaml +8 -0
- package/samples/notes-api/verification/components/notes-api.profile.yaml +15 -0
- package/samples/notes-api/verification/environments/local-notes.yaml +11 -0
- package/samples/notes-api/verification/environments/mock-notes.yaml +11 -0
- package/samples/notes-api/verification/fidelity/full-live-sandbox.yaml +7 -0
- package/samples/notes-api/verification/fidelity/mock-contract.yaml +6 -0
- package/samples/notes-api/verification/fixtures/existing-note.payload.yaml +15 -0
- package/samples/notes-api/verification/fixtures/existing-note.plan.yaml +9 -0
- package/samples/notes-api/verification/fixtures/existing-note.recipe.yaml +29 -0
- package/samples/notes-api/verification/hosts/local-process.yaml +27 -0
- package/samples/notes-api/verification/hosts/mock-loopback.yaml +14 -0
- package/samples/notes-api/verification/mocks/notes.responses.yaml +5 -0
- package/samples/notes-api/verification/personas/owner.yaml +16 -0
- package/samples/notes-api/verification/policies/no-authoring-inference.yaml +10 -0
- package/samples/notes-api/verification/runners/http.yaml +5 -0
- package/samples/notes-api/verification/surfaces/http-api.binding.yaml +11 -0
- package/samples/notes-api/verification/surfaces/http-api.pack.yaml +7 -0
- package/samples/notes-api/verification/workflow.yaml +27 -0
- package/samples/notes-browser/tracegrove/notes/browser.flow.yaml +19 -0
- package/samples/notes-browser/verification/cases/notes.browser.yaml +63 -0
- package/samples/notes-browser/verification/cases/notes.suite.yaml +4 -0
- package/samples/notes-browser/verification/runners/http.yaml +5 -0
- package/samples/notes-browser/verification/surfaces/http-api.binding.yaml +11 -0
- package/samples/notes-browser/verification/surfaces/http-api.pack.yaml +7 -0
- package/samples/notes-django/README.md +21 -0
- package/samples/notes-django/app/django_app.py +119 -0
- package/samples/notes-django/app/requirements.lock +4 -0
- package/samples/notes-mcp/app/mcp.mjs +47 -0
- package/samples/notes-mcp/tracegrove/notes.flow.yaml +20 -0
- package/samples/notes-mcp/tracegrove.config.yaml +13 -0
- package/samples/report-jobs/README.md +30 -0
- package/samples/report-jobs/app/jobs-api.mjs +65 -0
- package/samples/report-jobs/app/native-bridge.mjs +30 -0
- package/samples/report-jobs/app/store.mjs +74 -0
- package/samples/report-jobs/app/worker.mjs +22 -0
- package/samples/report-jobs/tracegrove/fixtures/failed-job.fixture.yaml +12 -0
- package/samples/report-jobs/tracegrove/fixtures/held-job.fixture.yaml +12 -0
- package/samples/report-jobs/tracegrove/fixtures/success-job.fixture.yaml +12 -0
- package/samples/report-jobs/tracegrove/reports/cancellation.flow.yaml +15 -0
- package/samples/report-jobs/tracegrove/reports/completion.flow.yaml +31 -0
- package/samples/report-jobs/tracegrove/reports/failure.flow.yaml +12 -0
- package/samples/report-jobs/tracegrove.config.yaml +10 -0
- package/samples/report-native/README.md +11 -0
- package/samples/report-native/tracegrove/cancellation.flow.yaml +11 -0
- package/samples/report-native/tracegrove/completion.flow.yaml +22 -0
- package/samples/report-native/tracegrove/failure.flow.yaml +7 -0
- package/samples/report-native/tracegrove.config.yaml +11 -0
- package/schema/tracegrove_cli-error_v1.json +156 -0
- package/schema/tracegrove_config_v1.json +233 -0
- package/schema/tracegrove_fixture_v1.json +297 -0
- package/schema/tracegrove_flow_v1.json +960 -0
- package/schema/tracegrove_recovery-status_v1.json +234 -0
- package/schema/tracegrove_run-video_v1.json +25 -0
- package/schema/workflow_action-registry_v1.json +303 -0
- package/schema/workflow_auth-recipe_v1.json +146 -0
- package/schema/workflow_boundary-observation_v1.json +515 -0
- package/schema/workflow_browser-command_v1.json +292 -0
- package/schema/workflow_browser-locator_v1.json +74 -0
- package/schema/workflow_browser-network-observation_v1.json +48 -0
- package/schema/workflow_browser-observation_v1.json +53 -0
- package/schema/workflow_budget-reservation_v1.json +150 -0
- package/schema/workflow_campaign-result_v1.json +382 -0
- package/schema/workflow_capability-artifact-manifest_v1.json +529 -0
- package/schema/workflow_capability-descriptor_v1.json +351 -0
- package/schema/workflow_capability-lifecycle-checkpoint_v1.json +510 -0
- package/schema/workflow_capability-observation_v1.json +1707 -0
- package/schema/workflow_capability-operation_v1.json +3212 -0
- package/schema/workflow_capability-replay-plan_v1.json +1247 -0
- package/schema/workflow_capability-retry-policy_v1.json +39 -0
- package/schema/workflow_capability-retry-state_v1.json +242 -0
- package/schema/workflow_case_v1.json +4222 -0
- package/schema/workflow_change-model_v1.json +614 -0
- package/schema/workflow_cleanup-expectation_v1.json +108 -0
- package/schema/workflow_cleanup-followup_v1.json +145 -0
- package/schema/workflow_component-profile_v1.json +219 -0
- package/schema/workflow_config_v1.json +180 -0
- package/schema/workflow_corpus_v1.json +172 -0
- package/schema/workflow_cost-observation_v1.json +366 -0
- package/schema/workflow_credential-lease_v1.json +222 -0
- package/schema/workflow_effective-config_v1.json +214 -0
- package/schema/workflow_environment-plan_v1.json +445 -0
- package/schema/workflow_environment_v1.json +1827 -0
- package/schema/workflow_evidence-projection_v1.json +636 -0
- package/schema/workflow_execution_v1.json +4086 -0
- package/schema/workflow_fidelity-plan_v1.json +512 -0
- package/schema/workflow_fidelity-profile_v1.json +396 -0
- package/schema/workflow_fixture-manifest_v1.json +918 -0
- package/schema/workflow_fixture-plan_v1.json +594 -0
- package/schema/workflow_git-source-request_v1.json +124 -0
- package/schema/workflow_git-source-resolution_v1.json +660 -0
- package/schema/workflow_git-source-snapshot_v1.json +287 -0
- package/schema/workflow_host-lease_v1.json +321 -0
- package/schema/workflow_host-observation_v1.json +282 -0
- package/schema/workflow_host-plan_v1.json +719 -0
- package/schema/workflow_identity-attestation_v1.json +412 -0
- package/schema/workflow_intelligence-policy_v1.json +153 -0
- package/schema/workflow_logical-payload_v1.json +206 -0
- package/schema/workflow_mcp-tool-call_v1.json +70 -0
- package/schema/workflow_mcp-tool-observation_v1.json +125 -0
- package/schema/workflow_mock-responses_v1.json +185 -0
- package/schema/workflow_native-job-action_v1.json +123 -0
- package/schema/workflow_native-job-observation_v1.json +138 -0
- package/schema/workflow_native-job-ready_v1.json +31 -0
- package/schema/workflow_native-job-request_v1.json +155 -0
- package/schema/workflow_native-job-response_v1.json +125 -0
- package/schema/workflow_ownership_v1.json +116 -0
- package/schema/workflow_persona_v1.json +499 -0
- package/schema/workflow_plan-edit-projection_v1.json +152 -0
- package/schema/workflow_plan-review_v1.json +246 -0
- package/schema/workflow_portable-environment-intent_v1.json +499 -0
- package/schema/workflow_portable-environment-profile_v1.json +1429 -0
- package/schema/workflow_portable-preflight_v1.json +2281 -0
- package/schema/workflow_qualification-admission_v1.json +467 -0
- package/schema/workflow_qualification-intent_v1.json +98 -0
- package/schema/workflow_qualification-policy_v1.json +109 -0
- package/schema/workflow_qualification-round_v1.json +226 -0
- package/schema/workflow_replay-assessment_v1.json +197 -0
- package/schema/workflow_replay-finding_v1.json +147 -0
- package/schema/workflow_request_v1.json +1567 -0
- package/schema/workflow_result-ingest_v1.json +343 -0
- package/schema/workflow_revisions_v1.json +334 -0
- package/schema/workflow_routing-decision_v1.json +482 -0
- package/schema/workflow_runner-capabilities_v1.json +316 -0
- package/schema/workflow_runner-profile_v1.json +119 -0
- package/schema/workflow_runner-protocol_v1_host.json +382 -0
- package/schema/workflow_runner-protocol_v1_plugin.json +491 -0
- package/schema/workflow_scenario-activation-intent_v1.json +346 -0
- package/schema/workflow_scenario-activation_v1.json +562 -0
- package/schema/workflow_scenario-projection_v1.json +221 -0
- package/schema/workflow_scenario-promotion_v1.json +455 -0
- package/schema/workflow_scenario-replay-assessment_v1.json +696 -0
- package/schema/workflow_scenario-revision-token_v1.json +115 -0
- package/schema/workflow_scenario-structure_v1.json +368 -0
- package/schema/workflow_scenario_v1.json +401 -0
- package/schema/workflow_scoped-resource_v1.json +550 -0
- package/schema/workflow_seed-recipe_v1.json +724 -0
- package/schema/workflow_selection_v1.json +1108 -0
- package/schema/workflow_signed-cleanup-followup_v1.json +175 -0
- package/schema/workflow_source-plan_v1.json +756 -0
- package/schema/workflow_source-selection_v1.json +456 -0
- package/schema/workflow_source-validation_v1.json +366 -0
- package/schema/workflow_step-event_v1.json +228 -0
- package/schema/workflow_stream-transcript_v1.json +1030 -0
- package/schema/workflow_suite_v1.json +64 -0
- package/schema/workflow_surface-binding_v1.json +411 -0
- package/schema/workflow_surface-pack_v1.json +159 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Attach a retained report to existing work
|
|
2
|
+
|
|
3
|
+
Receipt import and work attachment are separate delivery stages. An import can be
|
|
4
|
+
acknowledged while attachment is still prepared, unknown, or awaiting review.
|
|
5
|
+
Neither stage approves or completes work.
|
|
6
|
+
|
|
7
|
+
Bind the work before execution. For example, an operator-owned `work-binding.json`:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{"workId":"00000000-0000-4000-8000-000000000003","requirementRefs":[]}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Replace the example with the actual work UUID and agreed requirement refs. Empty
|
|
14
|
+
requirement refs do not assert a native work contract or permission to complete it.
|
|
15
|
+
Planning freezes the parsed binding into the request digest:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
tracegrove plan --config ./verification/workflow.yaml --purpose work_proof --work-binding ./work-binding.json --output ./request.json
|
|
19
|
+
tracegrove run --request ./request.json --state-dir ./run-state --json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
An unbound historical campaign cannot acquire a work binding during export.
|
|
23
|
+
Run a new, explicitly bound campaign if it is genuinely a new requested effort.
|
|
24
|
+
Normal unbound planning remains unchanged. SDK callers supply the same typed
|
|
25
|
+
`workBinding` to `plan`; it is copied and validated before planning.
|
|
26
|
+
|
|
27
|
+
Ingest and import the result using the [result sink](result-sink.md) and
|
|
28
|
+
[AWR delivery](awr-delivery.md). After import acknowledgement, create a protected
|
|
29
|
+
`target.json` with the actual work type, the same full UUID, its native workspace,
|
|
30
|
+
and the exact native `updated_at` value. Preserve timestamp precision and offset:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{"entityType":"task","entityId":"00000000-0000-4000-8000-000000000003","workspaceId":"00000000-0000-4000-8000-000000000001","expectedUpdatedAt":"2026-10-18T01:00:00.123456Z"}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
tracegrove report-prepare --sink ./retained-results --id <result-id> --target ./target.json --json
|
|
38
|
+
tracegrove report-inspect --sink ./retained-results --id <result-id> --json
|
|
39
|
+
tracegrove report-attach --sink ./retained-results --id <result-id> --json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Preparation and inspection are offline. Attachment uses the protected credential
|
|
43
|
+
environment described in the AWR guide. It calls the existing authenticated receipt
|
|
44
|
+
read endpoint with the frozen workspace UUID, then the existing artifact-create
|
|
45
|
+
endpoint with a stable Idempotency-Key header and deterministic artifact UUID.
|
|
46
|
+
The snapshot workspace must match the frozen import destination. Preparation
|
|
47
|
+
requires a timestamp supplied from an authorized native work read; it does not
|
|
48
|
+
fetch or invent one. The examples are placeholders, not observed work state.
|
|
49
|
+
The API receives `expected_scope.workspace_id` and
|
|
50
|
+
`expected_scope.expected_updated_at` on every attempt. The snapshot is a condition
|
|
51
|
+
on attachment admission, not proof that execution tested that work revision.
|
|
52
|
+
The returned artifact must match the exact workspace, work type/ID, report link,
|
|
53
|
+
evidence metadata, and artifact UUID before the sender records acknowledgement.
|
|
54
|
+
|
|
55
|
+
The report link is the existing private OrgX work-ledger receipt page. It does not
|
|
56
|
+
create another object store or save an expiring signed URL. Before each fresh
|
|
57
|
+
attachment attempt, the sender compares the full hosted receipt's canonical bytes
|
|
58
|
+
with the frozen receipt digest and freshly checks the retained local archive.
|
|
59
|
+
A substituted report, missing import, foreign target ID, or corrupted archive blocks
|
|
60
|
+
the attempt. Changing a target type, workspace or timestamp after preparation also
|
|
61
|
+
conflicts. Projects, initiatives, workstreams, milestones and tasks are supported.
|
|
62
|
+
|
|
63
|
+
The artifact is born `in_review`, with `external_unverified` provenance and an
|
|
64
|
+
explicit product verdict in its preview. A failed product campaign stays failed;
|
|
65
|
+
attaching its evidence does not label the product as passing. The link serves the
|
|
66
|
+
redacted imported report, not the full local bundle, recordings or raw observations.
|
|
67
|
+
Protected publication of those additional bytes remains a separate integration.
|
|
68
|
+
|
|
69
|
+
## Independent retries
|
|
70
|
+
|
|
71
|
+
The attachment outbox stores a separate immutable intent and acknowledgement from
|
|
72
|
+
the AWR import. Both stages reuse `LocalDeliveryJournal`, which owns bounded
|
|
73
|
+
attempt history, synced intent/attempt/acknowledgement records, version checks and
|
|
74
|
+
in-flight exclusion on the existing fenced ledger. Existing AWR journal event names
|
|
75
|
+
and receipt shapes remain readable; no migration or extra database is introduced.
|
|
76
|
+
|
|
77
|
+
If artifact creation succeeds but the response is lost, attachment becomes
|
|
78
|
+
`acknowledgement_unknown`. Reopen and retry with the same result ID: the exact
|
|
79
|
+
payload, artifact UUID and idempotency key are reused. A failed local acknowledgement
|
|
80
|
+
write is recovered the same way. Receipt import is not repeated, and no runner,
|
|
81
|
+
fixture seeder or completion service is invoked. A confirmed retry reports
|
|
82
|
+
`attached`, with a separate `recordedArtifactStatus`. Evaluation or human review
|
|
83
|
+
may have changed that status since creation; a retry records the returned status
|
|
84
|
+
without confusing it with delivery or native work acceptance. Historical
|
|
85
|
+
acknowledgement is not a fresh read; acknowledged retries make no network call.
|
|
86
|
+
|
|
87
|
+
The scoped intent uses `workflow.report-attachment/v2`. A v1 journal has no atomic
|
|
88
|
+
snapshot and is refused with a reconciliation message. Keep that journal and
|
|
89
|
+
reconcile any prior artifact with the original sender; this version does not
|
|
90
|
+
rewrite it, silently attach a snapshot later, or generate a replacement identity.
|
|
91
|
+
|
|
92
|
+
## Host authority and limits
|
|
93
|
+
|
|
94
|
+
`LocalReportAttachmentOutbox` exports typed `ReportAttachmentAuthority` and
|
|
95
|
+
`ReportAttachmentTransport` ports. The authority must resolve the target's actual
|
|
96
|
+
type, owner and workspace and authorize the side effects, including any artifact
|
|
97
|
+
evaluation costs. It is checked after readback and immediately before recording a
|
|
98
|
+
POST attempt. A lost response does not turn into a new approval grant.
|
|
99
|
+
|
|
100
|
+
The CLI represents a local operator's explicit configuration. Local labels and
|
|
101
|
+
no-op callbacks do not authenticate a tenant. Scoped attachment requires the
|
|
102
|
+
native API and migration in [OrgX #3663](https://github.com/hopeatina/orgx/pull/3663).
|
|
103
|
+
That transaction checks workspace ownership, locks the work target, and compares
|
|
104
|
+
the frozen workspace and timestamp before insertion. Matching historical retries
|
|
105
|
+
return the original artifact after a work change, subject to current workspace
|
|
106
|
+
access. The sender makes no separate mutable target read before POST and has no
|
|
107
|
+
unscoped fallback. An older strict API rejects the unknown scope field; a missing
|
|
108
|
+
native function must fail without a direct insert. Deploy the native migration
|
|
109
|
+
and API before using scoped delivery. Hosted tenant qualification still needs
|
|
110
|
+
live acceptance evidence; local transport tests do not establish it.
|
|
111
|
+
|
|
112
|
+
A native HTTP 409 produces a conflict with instructions to preserve the delivery
|
|
113
|
+
and reconcile its receipt. HTTP 400/401/403/404/422 blocks delivery and asks the
|
|
114
|
+
operator to check scope, access and contract support. Provider response text is
|
|
115
|
+
discarded. Connection loss, throttling and unavailable services retain an unknown
|
|
116
|
+
acknowledgement and the same retry key. None of these errors refreshes the
|
|
117
|
+
timestamp, strips the assertion, reimports the receipt or reruns the campaign.
|
|
118
|
+
|
|
119
|
+
`OrgxReportAttachmentHttpTransport` reuses the import transport's credential,
|
|
120
|
+
same-origin, redirect, deadline and bounded-response handling. It exposes no work
|
|
121
|
+
completion or outcome API. Full native proof, task acceptance, delayed outcomes,
|
|
122
|
+
live hosted qualification, and actual widget-host/mobile packs remain separate gates.
|
|
123
|
+
|
|
124
|
+
Conformance runs import/readback/attachment over real loopback HTTP with simulated
|
|
125
|
+
native authorization and storage. It drops the first artifact acknowledgement after
|
|
126
|
+
admission, reopens the sender, and requires one import, one artifact, identical POST
|
|
127
|
+
bytes, separate stage states, and no completion calls. It is not live OrgX evidence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tracegrove",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "tracegrove: behaviour tests against your real app, drafted by Claude Code or Codex, sealed as re-verifiable evidence.",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"engines": { "node": ">=22.22.0 <23" },
|
|
9
|
+
"bin": { "tracegrove": "./dist/cli/main.js", "workflow-verify": "./dist/cli/main.js" },
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./integrations/awr": { "types": "./dist/integrations/awr/index.d.ts", "default": "./dist/integrations/awr/index.js" },
|
|
14
|
+
"./authoring": { "types": "./dist/authoring/index.d.ts", "default": "./dist/authoring/index.js" },
|
|
15
|
+
".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
|
|
16
|
+
"./protocol": { "types": "./dist/protocol/index.d.ts", "default": "./dist/protocol/index.js" },
|
|
17
|
+
"./coordination": { "types": "./dist/core/coordination.d.ts", "default": "./dist/core/coordination.js" }
|
|
18
|
+
},
|
|
19
|
+
"files": ["dist", "schema", "samples", "docs/cleanup-followups.md", "docs/source-review.md", "docs/source-promotion.md", "docs/git-source-resolution.md", "docs/git-object-proof.md", "docs/local-review-store.md", "docs/local-scenario-store.md", "docs/local-execution-recovery.md", "docs/qualification-registration.md", "docs/qualification-results.md", "docs/replay-assessment.md", "docs/scenario-activation.md", "docs/scenario-structure.md", "docs/verified-bundles.md", "docs/developer-ux.md", "docs/architecture.md", "docs/browser-driver.md", "docs/portable-environments.md", "docs/examples/portable-environments", "docs/native-jobs.md", "docs/result-sink.md", "docs/awr-delivery.md", "docs/work-report-attachment.md", "docs/mcp-driver.md", "conformance/coordination-vectors.json", "LICENSE", "README.md", "docs/images/ui-run.png"],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc --project tsconfig.build.json && node scripts/copy-samples.mjs",
|
|
22
|
+
"typecheck": "tsc --project tsconfig.json --noEmit && tsc --project tsconfig.container.json --noEmit",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:conformance": "vitest run conformance/",
|
|
25
|
+
"test:django": "vitest run --config vitest.django.config.ts",
|
|
26
|
+
"test:container": "node scripts/container-conformance.mjs",
|
|
27
|
+
"schema:export": "node --import tsx scripts/export-schemas.ts",
|
|
28
|
+
"schema:check": "node --import tsx scripts/export-schemas.ts --check && node --import tsx scripts/export-environment-examples.ts --check",
|
|
29
|
+
"test:onboarding": "node scripts/readme-onboarding.mjs && node scripts/readme-onboarding-negative.mjs",
|
|
30
|
+
"verify": "npm run typecheck && npm run schema:check && npm run test"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"playwright": "1.64.1",
|
|
34
|
+
"yaml": "2.9.1",
|
|
35
|
+
"zod": "4.6.5"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": { "@modelcontextprotocol/sdk": "1.32.1", "@useorgx/agent-work-receipt": "0.3.0" },
|
|
38
|
+
"peerDependenciesMeta": { "@modelcontextprotocol/sdk": { "optional": true }, "@useorgx/agent-work-receipt": { "optional": true } },
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "1.32.1",
|
|
41
|
+
"@useorgx/agent-work-receipt": "0.3.0",
|
|
42
|
+
"@types/node": "22.19.1",
|
|
43
|
+
"tsx": "4.23.15",
|
|
44
|
+
"typescript": "5.9.3",
|
|
45
|
+
"vitest": "5.0.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Test-mode auth: tracegrove issues one random bearer token per persona per run."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
TOKENS = json.loads(os.environ.get("TRACEGROVE_TOKENS", "{}"))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def tracegrove_auth(get_response):
|
|
9
|
+
def middleware(request):
|
|
10
|
+
header = request.headers.get("Authorization", "")
|
|
11
|
+
request.subject = TOKENS.get(header.removeprefix("Bearer "))
|
|
12
|
+
return get_response(request)
|
|
13
|
+
|
|
14
|
+
return middleware
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
initial = True
|
|
8
|
+
dependencies = []
|
|
9
|
+
operations = [
|
|
10
|
+
migrations.CreateModel(
|
|
11
|
+
name="Note",
|
|
12
|
+
fields=[
|
|
13
|
+
("id", models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
|
14
|
+
("owner", models.CharField(max_length=200)),
|
|
15
|
+
("title", models.CharField(max_length=200)),
|
|
16
|
+
("body", models.TextField()),
|
|
17
|
+
],
|
|
18
|
+
),
|
|
19
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Note(models.Model):
|
|
7
|
+
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
|
8
|
+
owner = models.CharField(max_length=200)
|
|
9
|
+
title = models.CharField(max_length=200)
|
|
10
|
+
body = models.TextField()
|
|
11
|
+
|
|
12
|
+
def as_json(self):
|
|
13
|
+
return {"id": str(self.id), "owner": self.owner, "title": self.title, "body": self.body}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from django.http import HttpResponse, JsonResponse
|
|
4
|
+
|
|
5
|
+
from .models import Note
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def health(request):
|
|
9
|
+
return JsonResponse({"ok": True})
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def notes(request):
|
|
13
|
+
if not request.subject:
|
|
14
|
+
return JsonResponse({"error": "unauthorized"}, status=401)
|
|
15
|
+
if request.method == "POST":
|
|
16
|
+
data = json.loads(request.body or "{}")
|
|
17
|
+
note = Note.objects.create(owner=request.subject, title=data["title"], body=data["body"])
|
|
18
|
+
return JsonResponse({"note": note.as_json()}, status=201)
|
|
19
|
+
return JsonResponse({"notes": [n.as_json() for n in Note.objects.filter(owner=request.subject)]})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def note(request, note_id):
|
|
23
|
+
if not request.subject:
|
|
24
|
+
return JsonResponse({"error": "unauthorized"}, status=401)
|
|
25
|
+
found = Note.objects.filter(id=note_id).first()
|
|
26
|
+
if found is None:
|
|
27
|
+
return JsonResponse({"error": "not_found"}, status=404)
|
|
28
|
+
if found.owner != request.subject:
|
|
29
|
+
return JsonResponse({"error": "forbidden"}, status=403)
|
|
30
|
+
if request.method == "DELETE":
|
|
31
|
+
found.delete()
|
|
32
|
+
return HttpResponse(status=204)
|
|
33
|
+
return JsonResponse({"note": found.as_json()})
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Tracegrove sample: minimal Django notes API. The database lives in the per-run data dir."""
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
SECRET_KEY = "tracegrove-sample-not-secret"
|
|
5
|
+
DEBUG = True
|
|
6
|
+
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
|
|
7
|
+
INSTALLED_APPS = ["notes"]
|
|
8
|
+
MIDDLEWARE = ["notes.auth.tracegrove_auth"]
|
|
9
|
+
ROOT_URLCONF = "notesite.urls"
|
|
10
|
+
DATABASES = {
|
|
11
|
+
"default": {
|
|
12
|
+
"ENGINE": "django.db.backends.sqlite3",
|
|
13
|
+
"NAME": os.path.join(os.environ.get("TRACEGROVE_DATA_DIR", "."), "db.sqlite3"),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|
17
|
+
USE_TZ = True
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
django==6.1.2
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
title: Create, read, deny a stranger and delete a note
|
|
2
|
+
tags: [notes]
|
|
3
|
+
steps:
|
|
4
|
+
- name: create
|
|
5
|
+
POST: /notes
|
|
6
|
+
json: { title: Fresh note, body: from Django }
|
|
7
|
+
expect: 201
|
|
8
|
+
save: { noteId: note.id }
|
|
9
|
+
|
|
10
|
+
- name: read back
|
|
11
|
+
GET: /notes/{noteId}
|
|
12
|
+
observe: true
|
|
13
|
+
expect: { status: 200, json: { note.title: Fresh note } }
|
|
14
|
+
|
|
15
|
+
- name: intruder is denied
|
|
16
|
+
GET: /notes/{noteId}
|
|
17
|
+
as: intruder
|
|
18
|
+
expect: { status: 403, absent: [note] }
|
|
19
|
+
|
|
20
|
+
- name: delete
|
|
21
|
+
DELETE: /notes/{noteId}
|
|
22
|
+
expect: 204
|
|
23
|
+
|
|
24
|
+
- name: gone
|
|
25
|
+
GET: /notes/{noteId}
|
|
26
|
+
observe: true
|
|
27
|
+
expect: 404
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Tracegrove sample: a FastAPI notes API backed by SQLite in the per-run data dir."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sqlite3
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from fastapi import Depends, FastAPI, Header, HTTPException, Response
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
DB = os.path.join(os.environ.get("TRACEGROVE_DATA_DIR", "."), "notes.sqlite3")
|
|
11
|
+
# Test-mode auth: tracegrove issues one random bearer token per persona per run.
|
|
12
|
+
TRACEGROVE_TOKENS = json.loads(os.environ.get("TRACEGROVE_TOKENS", "{}"))
|
|
13
|
+
|
|
14
|
+
app = FastAPI()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def db() -> sqlite3.Connection:
|
|
18
|
+
conn = sqlite3.connect(DB)
|
|
19
|
+
conn.row_factory = sqlite3.Row
|
|
20
|
+
conn.execute("create table if not exists notes (id text primary key, owner text, title text, body text)")
|
|
21
|
+
return conn
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def current_user(authorization: str = Header("")) -> str:
|
|
25
|
+
subject = TRACEGROVE_TOKENS.get(authorization.removeprefix("Bearer "))
|
|
26
|
+
if not subject:
|
|
27
|
+
raise HTTPException(status_code=401, detail="unauthorized")
|
|
28
|
+
return subject
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NoteIn(BaseModel):
|
|
32
|
+
title: str
|
|
33
|
+
body: str
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.get("/health")
|
|
37
|
+
def health():
|
|
38
|
+
return {"ok": True}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.post("/notes", status_code=201)
|
|
42
|
+
def create(note: NoteIn, user: str = Depends(current_user)):
|
|
43
|
+
row = {"id": str(uuid.uuid4()), "owner": user, "title": note.title, "body": note.body}
|
|
44
|
+
with db() as conn:
|
|
45
|
+
conn.execute("insert into notes values (:id, :owner, :title, :body)", row)
|
|
46
|
+
return {"note": row}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def owned(note_id: str, user: str) -> dict:
|
|
50
|
+
with db() as conn:
|
|
51
|
+
row = conn.execute("select * from notes where id = ?", (note_id,)).fetchone()
|
|
52
|
+
if row is None:
|
|
53
|
+
raise HTTPException(status_code=404, detail="not_found")
|
|
54
|
+
if row["owner"] != user:
|
|
55
|
+
raise HTTPException(status_code=403, detail="forbidden")
|
|
56
|
+
return dict(row)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@app.get("/notes/{note_id}")
|
|
60
|
+
def read(note_id: str, user: str = Depends(current_user)):
|
|
61
|
+
return {"note": owned(note_id, user)}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@app.delete("/notes/{note_id}", status_code=204)
|
|
65
|
+
def delete(note_id: str, user: str = Depends(current_user)):
|
|
66
|
+
owned(note_id, user)
|
|
67
|
+
with db() as conn:
|
|
68
|
+
conn.execute("delete from notes where id = ?", (note_id,))
|
|
69
|
+
return Response(status_code=204)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
title: Create, read, deny a stranger and delete a note
|
|
2
|
+
tags: [notes]
|
|
3
|
+
steps:
|
|
4
|
+
- name: create
|
|
5
|
+
POST: /notes
|
|
6
|
+
json: { title: Fresh note, body: from FastAPI }
|
|
7
|
+
expect: 201
|
|
8
|
+
save: { noteId: note.id }
|
|
9
|
+
|
|
10
|
+
- name: read back
|
|
11
|
+
GET: /notes/{noteId}
|
|
12
|
+
observe: true
|
|
13
|
+
expect: { status: 200, json: { note.title: Fresh note } }
|
|
14
|
+
|
|
15
|
+
- name: intruder is denied
|
|
16
|
+
GET: /notes/{noteId}
|
|
17
|
+
as: intruder
|
|
18
|
+
expect: { status: 403, absent: [note] }
|
|
19
|
+
|
|
20
|
+
- name: delete
|
|
21
|
+
DELETE: /notes/{noteId}
|
|
22
|
+
expect: 204
|
|
23
|
+
|
|
24
|
+
- name: gone
|
|
25
|
+
GET: /notes/{noteId}
|
|
26
|
+
observe: true
|
|
27
|
+
expect: 404
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Tracegrove sample: a real file-backed notes API. No dependencies. Not a mock.
|
|
2
|
+
// Env: PORT, NOTES_DIR, NOTES_TOKENS (JSON object token -> userId), NOTES_BUILD (display only).
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, readdirSync, existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { send, readBody } from './http.mjs';
|
|
8
|
+
|
|
9
|
+
const port = Number(process.env.PORT ?? 0);
|
|
10
|
+
const dir = process.env.NOTES_DIR ?? './notes-data';
|
|
11
|
+
const tokens = JSON.parse(process.env.NOTES_TOKENS ?? '{}');
|
|
12
|
+
const build = process.env.NOTES_BUILD ?? 'dev';
|
|
13
|
+
mkdirSync(dir, { recursive: true });
|
|
14
|
+
|
|
15
|
+
function notePath(id) { if (!/^[0-9a-f-]{36}$/.test(id)) return null; return join(dir, `${id}.json`); }
|
|
16
|
+
function readNote(id) { const p = notePath(id); if (!p || !existsSync(p)) return null; return JSON.parse(readFileSync(p, 'utf8')); }
|
|
17
|
+
function writeNote(note) { const p = notePath(note.id); const tmp = `${p}.tmp`; writeFileSync(tmp, JSON.stringify(note)); renameSync(tmp, p); }
|
|
18
|
+
|
|
19
|
+
const server = createServer(async (req, res) => {
|
|
20
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
21
|
+
if (req.method === 'GET' && url.pathname === '/health') {
|
|
22
|
+
const count = readdirSync(dir).filter((f) => f.endsWith('.json')).length;
|
|
23
|
+
return send(res, 200, { ok: true, build, notes: count });
|
|
24
|
+
}
|
|
25
|
+
const auth = req.headers.authorization ?? '';
|
|
26
|
+
const token = auth.startsWith('Bearer ') ? auth.slice(7) : null;
|
|
27
|
+
const userId = token ? tokens[token] : undefined;
|
|
28
|
+
if (!userId) return send(res, 401, { error: 'unauthorized' });
|
|
29
|
+
if (req.method === 'GET' && url.pathname === '/ui') {
|
|
30
|
+
res.writeHead(200, { 'content-type': 'text/html' });
|
|
31
|
+
res.end(`<!doctype html><html lang="en"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Notes</title>
|
|
32
|
+
<main><h1>Notes</h1><button onclick="fetch('/notes').then(r=>r.json()).then(data=>document.querySelector('[role=status]').textContent=data.notes.map(n=>n.title).join(', '))">Refresh</button>
|
|
33
|
+
<p role="status" data-testid="notes">Not loaded</p></main></html>`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const match = url.pathname.match(/^\/notes(?:\/([^/]+))?$/);
|
|
37
|
+
if (!match) return send(res, 404, { error: 'not_found' });
|
|
38
|
+
const id = match[1];
|
|
39
|
+
try {
|
|
40
|
+
if (req.method === 'POST' && !id) {
|
|
41
|
+
const body = await readBody(req);
|
|
42
|
+
if (typeof body.title !== 'string' || typeof body.body !== 'string') return send(res, 400, { error: 'invalid_note' });
|
|
43
|
+
const note = { id: randomUUID(), title: body.title, body: body.body, ownerId: userId, createdAt: new Date().toISOString() };
|
|
44
|
+
writeNote(note);
|
|
45
|
+
return send(res, 201, { note });
|
|
46
|
+
}
|
|
47
|
+
if (req.method === 'GET' && !id) {
|
|
48
|
+
const notes = readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => JSON.parse(readFileSync(join(dir, f), 'utf8'))).filter((n) => n.ownerId === userId);
|
|
49
|
+
return send(res, 200, { notes });
|
|
50
|
+
}
|
|
51
|
+
if (id) {
|
|
52
|
+
const note = readNote(id);
|
|
53
|
+
if (!note) return send(res, 404, { error: 'not_found' });
|
|
54
|
+
if (note.ownerId !== userId) return send(res, 403, { error: 'forbidden' });
|
|
55
|
+
if (req.method === 'GET') return send(res, 200, { note });
|
|
56
|
+
if (req.method === 'DELETE') { unlinkSync(notePath(id)); return send(res, 204); }
|
|
57
|
+
}
|
|
58
|
+
return send(res, 405, { error: 'method_not_allowed' });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return send(res, 400, { error: 'bad_request', detail: String(error && error.message) });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
server.listen(port, '127.0.0.1', () => {
|
|
64
|
+
const address = server.address();
|
|
65
|
+
process.stdout.write(`listening ${typeof address === 'object' && address ? address.port : port}\n`);
|
|
66
|
+
});
|
|
67
|
+
process.on('SIGTERM', () => server.close(() => process.exit(0)));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export function send(res, status, body) {
|
|
4
|
+
const text = body === undefined ? '' : JSON.stringify(body);
|
|
5
|
+
res.writeHead(status, { 'content-type': 'application/json', 'x-request-id': randomUUID(), 'content-length': Buffer.byteLength(text) });
|
|
6
|
+
res.end(text);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function readBody(req) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
let data = ''; req.setEncoding('utf8');
|
|
12
|
+
req.on('data', chunk => { data += chunk; if (data.length > 65536) { reject(new Error('too large')); req.destroy(); } });
|
|
13
|
+
req.on('end', () => { try { resolve(data ? JSON.parse(data) : {}); } catch (error) { reject(error); } });
|
|
14
|
+
req.on('error', reject);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
create:
|
|
2
|
+
POST: /notes
|
|
3
|
+
json: { title: Existing note, body: { words: 6 } }
|
|
4
|
+
expect: 201
|
|
5
|
+
save: { noteId: note.id }
|
|
6
|
+
readback:
|
|
7
|
+
GET: /notes/{noteId}
|
|
8
|
+
expect: { status: 200, json: { note.title: Existing note } }
|
|
9
|
+
cleanup:
|
|
10
|
+
DELETE: /notes/{noteId}
|
|
11
|
+
expect: 204
|
|
12
|
+
gone: { GET: "/notes/{noteId}", status: 404 }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
title: Create a note, read it back, deny a stranger, delete it and keep other notes intact
|
|
2
|
+
risk: critical
|
|
3
|
+
tags: [notes, authz]
|
|
4
|
+
given:
|
|
5
|
+
existing: existing-note
|
|
6
|
+
steps:
|
|
7
|
+
- name: create
|
|
8
|
+
POST: /notes
|
|
9
|
+
json: { title: Fresh note, body: Written through the real API. }
|
|
10
|
+
expect: { status: 201 }
|
|
11
|
+
save: { noteId: note.id }
|
|
12
|
+
|
|
13
|
+
- name: read back
|
|
14
|
+
GET: /notes/{noteId}
|
|
15
|
+
observe: true
|
|
16
|
+
expect: { status: 200, json: { note.title: Fresh note, note.body: Written through the real API. } }
|
|
17
|
+
|
|
18
|
+
- name: intruder is denied
|
|
19
|
+
GET: /notes/{noteId}
|
|
20
|
+
as: intruder
|
|
21
|
+
expect: { status: 403, absent: [note] }
|
|
22
|
+
|
|
23
|
+
- name: delete
|
|
24
|
+
DELETE: /notes/{noteId}
|
|
25
|
+
expect: 204
|
|
26
|
+
|
|
27
|
+
- name: gone
|
|
28
|
+
GET: /notes/{noteId}
|
|
29
|
+
observe: true
|
|
30
|
+
expect: 404
|
|
31
|
+
|
|
32
|
+
- name: existing note untouched
|
|
33
|
+
GET: /notes/{existing.noteId}
|
|
34
|
+
observe: true
|
|
35
|
+
expect: { status: 200, json: { note.title: Existing note } }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
title: A new note shows up in the owner's list and nowhere else
|
|
2
|
+
tags: [notes, smoke]
|
|
3
|
+
steps:
|
|
4
|
+
- name: create
|
|
5
|
+
POST: /notes
|
|
6
|
+
json: { title: Listed note, body: visible to its owner }
|
|
7
|
+
expect: 201
|
|
8
|
+
save: { noteId: note.id }
|
|
9
|
+
|
|
10
|
+
- name: owner sees it
|
|
11
|
+
GET: /notes
|
|
12
|
+
expect:
|
|
13
|
+
status: 200
|
|
14
|
+
count: { notes: 1 }
|
|
15
|
+
json: { "notes[0].title": Listed note }
|
|
16
|
+
|
|
17
|
+
- name: stranger sees an empty list
|
|
18
|
+
GET: /notes
|
|
19
|
+
as: intruder
|
|
20
|
+
expect: { status: 200, count: { notes: 0 } }
|
|
21
|
+
|
|
22
|
+
- name: anonymous is rejected
|
|
23
|
+
GET: /notes
|
|
24
|
+
as: none
|
|
25
|
+
expect: 401
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
project: notes
|
|
2
|
+
app:
|
|
3
|
+
adapter: node
|
|
4
|
+
entry: app/app.mjs
|
|
5
|
+
health: /health
|
|
6
|
+
sources: [app/**]
|
|
7
|
+
env:
|
|
8
|
+
NOTES_BUILD: sample
|
|
9
|
+
inject:
|
|
10
|
+
port: PORT
|
|
11
|
+
dataDir: NOTES_DIR
|
|
12
|
+
tokens: NOTES_TOKENS
|
|
13
|
+
personas:
|
|
14
|
+
owner: { subject: alice }
|
|
15
|
+
intruder: { subject: bob }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
schemaVersion: workflow.action-registry/v1
|
|
2
|
+
ref: { id: example.actions.notes, revision: "1" }
|
|
3
|
+
actions:
|
|
4
|
+
- { actionId: notes.create/v1, kind: http.request, effect: create, method: POST, path: /notes, body: { title: "{title}", body: "{body}" }, auth: { kind: persona }, expectStatus: 201, captures: [ { name: noteId, from: json, path: note.id } ] }
|
|
5
|
+
- { actionId: notes.read/v1, kind: http.request, effect: read, method: GET, path: "/notes/{noteId}", body: null, auth: { kind: persona }, expectStatus: null, captures: [] }
|
|
6
|
+
- { actionId: notes.delete/v1, kind: http.request, effect: delete, method: DELETE, path: "/notes/{noteId}", body: null, auth: { kind: persona }, expectStatus: 204, captures: [] }
|