What you will take away from this lesson
A script runs when nobody is watching. That is the point of it, and it is also the reason the question of what a run may do has to be answered before the first schedule fires. The answer on Plexara is short: a run may do exactly what its author could do at the keyboard on the day the version was saved, and every step it takes is written down.
This lesson is the governance half of the series. It covers the authority a run carries, what a save requires before anything is stored, the agreement a change in behavior waits for, why the language itself cannot reach outside the platform, the lifecycle of a script, who sees what, what a failed run keeps, and the view an administrator gets of all of it.
Learning Objectives
- 01State the authority rule: a run presents the roles its author held at the save, every call is authorized at that moment, and narrowing the persona takes effect on the next run.
- 02Know what a save requires: one format, work in main(), the structural rules, tests that pass, reach the code, and read the data, and no credential-shaped literal.
- 03Explain what happens when a new version would change what an automation does: the replay against past runs, and the plain-language summary the person agrees to before the save goes through.
- 04Explain why a script cannot reach out: no network, no filesystem, no clock, no imports beyond pinned libraries, and every action a platform call audited under the script’s own identity.
- 05Read the lifecycle, active through disabled, deprecated, and superseded, and what each state does to runs and schedules.
- 06Know who sees what: a script’s definition is everyone’s, its runs’ detail and its state are its owner’s, and libraries are shared by anyone who loads them.
- 07Know what a failed run keeps: state saved only on success, and a checkpoint committed however the run ends.
- 08Understand an administrator’s transfer of ownership and what it changes, and find the administrator’s view of every script and every run.
Where this lesson sits
Lessons 602 through 604 built a script, gave it outputs, and put it on a schedule. This lesson steps back and asks what that schedule is allowed to do while nobody is watching, and what it leaves behind so that somebody can check later.
600 Series: Automations
- 601Do not spend AI on what a script can doThe automation gap, what integration platforms and laptop scripts each cost, and the division of labor: a script for the deterministic part, the model for writing it and for judgment.
- 602The agent writes the first scriptThe loop from a recorded draft through tests to the save, what a save requires, what validate and a dry run report, the dialect’s deliberate absences, the traps that fail a draft, and the script’s page in the portal.
- 603Outputs: feeds, reports, and dashboards that refresh themselvesOutput identity across runs, tables and documents, the semi-dynamic dashboard and its data region, the referencing pattern, version caps, and delivery to a bucket drop.
- 604Running it: by hand, from the portal, and on a scheduleThree triggers, the cadence builder, the pinned fire date, what a schedule guarantees, and the run history with every trigger, duration, output, and log.
- 605What a run may do, and the record it leavesThe authority a run carries, what a save refuses, why the language cannot reach out, the lifecycle, ownership and transfer, and the administrator’s view.
- 606Scripts as skills: the weekly review the agent runs on your businessThree scripts attached to one prompt, the agent running them and reading the outputs against the knowledge graph, and a weekly list of action items with the figures behind them.
- 607Events in: a webhook source, its table, and an automation that reads itCreating a source, how a sender proves itself and what it is told, the table that serves events from acknowledgement, compaction and retention, the Webhooks page, and an automation that reads only what is new.
- 608Results out: notification channels and signed delivery to other systemsChannel kinds and who may send to them, sending from a session and from an automation, the delivery history and the retry rule, the JSON envelope a system routes on, signed requests, and delivery to another deployment.
The 600 series picks up the registered table from the 500 series and the prompt mechanics from the 400 series. It is the last numbered series in the curriculum.
What a save requires
A save is the version that runs, so the checks that protect a run happen at the save, where the author can fix the problem, rather than at the next fire. They are written for the agent that writes the script: a person who asks for an automation never reads the code and never sees a finding.
What a save requires
One format
Rewritten, never refused.
The source is stored in one canonical layout, every comment kept, so what is read back is what runs and a diff between two versions shows only what changed. Source already in that layout is stored byte for byte.
The work in main()
Refused until it is.
The platform calls main() after the script loads. The top level holds functions, constants written as literals, and docstrings, which keeps each part of the script testable on its own. A source with no main() is saved as a library.
The structural rules
Refused, naming the rule, the line, and the fix.
Functions that are too long, too branched, or nested too deep; a local or parameter never read; a name that hides a built-in; a function with no docstring; SQL assembled from values instead of bound with params; a platform call made once per element of a collection.
Tests that pass and reach the code
Refused, naming the lines no test reached.
At least one test, every test passing, and at least 80% of the script’s statements reached. A test that makes no assertion is refused.
Tests that read the data
Refused, naming what went unread.
A test that still passes when the rows it replays are altered (the last row dropped, the first row’s values changed) is blind to its data and is refused. Together the tests must assert on every output they produce: each column of each export, the staged state, each notification, and the run’s result.
Recorded calls
What a test runs against.
Every draft run and every run records each host call it makes and the answer it got. A test replays a recording, or declares the answer a call gets with testing.answer, so a test never reaches an upstream and can take the branch no draft takes.
No credential-shaped literal
Refused for a known format; a warning for a name.
A private key header, a cloud access key id, a well-known token format, or a URL with a password in it blocks the save. A variable merely named like a secret is a warning. The scan is a tripwire that catches a paste, not a guarantee; scripts name connections, and Plexara holds the credentials.
Source that parses
Refused at the keyboard.
Code that cannot run is refused rather than stored, so the failure surfaces while somebody is looking at it instead of at the next fire.
The same checks apply to every save, from the agent or from the portal editor, including the next edit of a script saved before the rules existed. They are checked at the save, never at a run, so an older script keeps running as it is until somebody saves it again. An output addressed to a destination Plexara does not have is reported by validate rather than refused at the save, because refusing the save would also refuse the edit that fixes it.
The test report a save keeps
The tests travel with the version they proved. The script’s Tests tab shows the report from its save, so anyone who opens the automation can see what its tests reached and that each one passed.

When a new version changes what the automation does
Passing its own tests shows a version is internally sound. It does not show the version still does what the person relied on. So a new version of a script that has run is replayed against the recordings of its most recent successful runs, through both the saved source and the new one, and the two are compared.
A new version, replayed against the old one
Compared across the five most recent successful runs
- The rows each output produces, its columns, and their types
- The state the run would save
- The notifications it would post
- The result it hands back
- What it reaches: tools, connections, and destinations
- Nothing differs
- The save goes through. This is how a refactor is shown to be safe: the new version produced what the old one did from the same recorded inputs.
- Something differs
- The save is refused, naming each difference, until it carries a plain-language summary of what the automation will now do differently and the agent’s confirmation that the person it runs for agreed (change_summary and user_agreed). Both are kept on the version with who saved it and when.
The person approves behavior, never code. There is no reviewer role, no queue, and no second approver. The script’s page lists every version’s summary under What changed, with who saved it and when it was agreed, and shows no code, diff, or test output there.
Why the language cannot reach out
The dialect a script is written in is deliberately small, and the absences are the security model. A script has no way to open a connection, read a disk, tell the time, or pull in code from outside the platform, so the only outside world it has is the platform, and the platform records everything it is asked to do.
Why the language cannot reach out
No network
A script opens no socket and supplies no endpoint. An external API is reached only through a connection Plexara already holds, with platform.call, so what a script can reach is what its author can reach.
No filesystem
A file is read through the registered table or a platform call, and written as an output. Nothing lands anywhere the platform does not record.
No clock, no randomness
The fire time is pinned on the run, so the same version with the same parameters asks the same question. A run may ask how long it has left before its time limit, and that answer is recorded with the run like any call’s, so a replay reads the same number. A run nobody can reproduce is not a governed run.
No imports, only libraries
A script starts with platform, json, xml, date, run, sum, and fail, and a test also has testing and assert. load() brings in a saved library at a named version and nothing else, and a library version never changes, so the program is the source on the version plus library code that cannot move under it.
Everything a script does is therefore a platform call, over the same governed path an agent’s call takes, and every one of them is audited under script:<name>. A run’s reach can be read from its source before it runs, which is what validate reports, and its record is complete after.
The lifecycle
A script is in one of four states, and the state is the only thing that decides whether a saved version’s run is admitted. There is no approval queue and no reviewer between a save and a run; a save that changes what the automation does waits only for the agreement of the person it runs for, recorded on the version. After the save, the lifecycle is what can take a script out of service in one action, and it says so wherever the script is shown.
The lifecycle of a script
- 1
Active
The saved version runs: from any session, from the Run button, and on its schedule.
- 2
Disabled
Nothing executes it. The run gate refuses in its own words on every surface, and a cadence set on a disabled script saves and stays inert, which the tool and the page both say plainly.
- 3
Deprecated
Taken out of service and marked as such. The record stays; runs are refused.
- 4
Superseded
Retired in favor of a named replacement. The reference to the old script still resolves, and says which script replaced it.
There is no approval queue and no reviewer between a save and a run. What stands in front of a version is the save itself: its checks, and the person’s agreement when the version changes what the automation does. Once saved it runs; taking it out of service is the only gate after that, and a schedule is never deleted, only disabled, so the row that explains past runs stays.
Who sees what
A script is how a report or a file somebody was given was produced, so its definition is open: everyone signed in can read what it is, its source, its versions, and how its runs have gone. Acting on it, and reading what a run was given and printed, stays with its owner and administrators. The team shares the outputs, which have the sharing model of every other asset, and the libraries scripts load.
Who sees what
Everyone signed in
Every automation and schedule, and each script’s definition: what it is, its parameters, whether a run would be admitted, its schedule, its source, and its version history. Its run history too, as how each run went, when, how long it took, and why one failed. Reading a script grants nothing; a run still presents its author’s captured roles.
Its owner and administrators
What each run was given, printed, and wrote; the state; the roles each version’s author held at the save; and every action: running, editing, scheduling, granting, and deleting.
A persona, role, or API key granted its runs
The right to start a run and read the runs it started, with their outputs. A grant decides who may ask for a run, never what the run may reach, and it cannot change the script.
Whoever asked for one run
That run: its parameters, outputs, and log.
The team
The outputs, under the sharing model of every other asset, and the libraries. Anyone can load any library, so the pagination, date windows, and table shaping many scripts repeat are written once and shared.
A prompt that references a script resolves it for every signed-in reader; the last successful run and what it produced come with it only for the owner and administrators. The way a whole team benefits from one person’s script is the way 606 shows: the review it produces is shared, and the script stays its owner’s to run and change.
Ownership and transfer
Because a script is personal, someone leaving the team or changing roles is a real event for the automations they own. An administrator can move a script to another person, and the move changes more than a name on a listing.
Ownership, and an administrator’s transfer
Only an administrator moves a script
From the script’s page, choosing the new owner from the people who have signed in to your deployment at least once. An owner cannot give a script away.
The whole script moves at once
What the owner sees, edits, runs, and schedules, and the history: the new owner reads the run records and dry-run accounts the previous owner produced.
The move is a version, authored by the administrator
From then on a run presents that administrator’s roles. Moving a script to an administrator is how it comes to run with an administrator’s reach.
A name clash is refused
If the receiving owner already keeps a script of the same name, the transfer does not happen.
It is audited
Like every other administrative write, the transfer is recorded in the audit log.
The transfer control
The transfer is done on the script’s own page, the same page the owner reads it on. It is the one thing that page offers an administrator and not an owner.

The record a run leaves
Every run writes a row: the version that executed, what triggered it, how long it took, the outputs it wrote and the asset versions they became, and the log the script printed. Every call the run made is also in the audit log under the script’s own principal. The trace below is the last successful run of the margin script from 604, read back.
One run, and the record it leaves
What the agent calls. This is the exchange the agent has with Plexara on your behalf, shown for the technical reader. You ask in plain language; you never type any of it.
run_script name=acme-supplier-margin args={"month":"2025-12-01","conn":"acme","mode":"refresh"}
→ status succeeded version 6 trigger tool duration 8,231 ms
outputs
supplier-margin-by-category csv asset 871da875-cd99-44f9-b6d9-55732b4e9086 version 3
supplier-margin-feed json asset 589855b4-cfe1-4355-af26-ae68cbc5770f version 3
supplier-margin-dashboard refresh asset bab7c8e7-67e6-4561-834a-32524f203fc8 version 2
audited as script:acme-supplier-margin, presenting the roles captured at the save of version 6The run row names the version that executed, what triggered it, how long it took, every output it wrote with the asset version it produced, and the log it printed. The audit log records each call the run made under the script’s own principal. Between the two, a reader six months later can say exactly what happened and under whose authority.
Versions, their test reports, and the dry-run account
The version history is the other half of the record. Each version names who saved it and the roles a run of it presents, keeps the test report from its save, and carries the change summary when it changed what the automation does. It also carries the account of the dry run that preceded it, if there was one. A version nobody dry-ran is called out as code that first executed unattended.

What a version keeps from its save
- Who saved it, and their roles
- The author and the roles they held at the save, which are the roles a run of the version presents.
- The test report
- How each test did at the save and the share of statements they reached, with the lines no test reaches. The Tests tab shows it, and the flow diagram marks each step the tests miss. A version saved without a source change, such as an ownership transfer, keeps the report of the version before it.
- The change summary
- When the version changed what the automation does: the plain-language summary, and when the person agreed to it.
What a dry-run account holds
- Who ran it, and when
- The author’s own identity, under their own persona.
- How it ended
- Succeeded, or the failure and the line it failed on.
- What it printed
- The bounded log, head kept, tail dropped with a marker when it overflows.
- The shape of its outputs
- Each export’s format, row count, and size, measured without being written.
- Which source it executed
- The account is keyed to the exact source, so it attaches to whichever version later carries that code. A version with no account is code that first executed unattended, and the version detail says so.
State, and what a failed run keeps
An incremental job carries a watermark or a cursor from one run to the next in its state. Whether that state moves when a run fails decides whether the next run repeats work or skips it, so the rule is explicit: saved state moves only on success, and a checkpoint moves however the run ends.
State, and what a failed run keeps
platform.save_state(obj)
Committed only when the run succeeds.
Applied in the same step that marks the run succeeded, with a compare-and-set on the revision the run read. A failed run leaves the state where it was, so a watermark never moves past work that did not happen.
platform.checkpoint(obj)
Committed however the run ends.
Stages progress the platform keeps when the run fails or is halted at its time limit, so a pipeline that merged half its pages does not lose its place for all of them. A successful run commits its save_state, or its last checkpoint if it never called save_state.
A checkpoint that loses the compare-and-set
The run stays failed for its own reason.
Another run wrote the state first. The checkpoint is refused and the refusal is recorded beside the run’s own failure, which it does not replace.
platform.remaining_ms()
How long the run has left.
A script has no clock, so this is how a long job decides to checkpoint and stop before its time limit rather than be halted mid-page. The value is recorded with the run, so a test replays it exactly.
fail() after save_state
A warning at the save, not a refusal.
A failed run’s save_state is discarded, so a function that saves state and then fails never writes it. The save says so, and a draft run reports the staged value as discarded rather than saved.
State is one JSON object per script, at most 64 KiB, for either call. It belongs to the script rather than to a version, so it survives a new version, a disable, and an ownership transfer. The run page labels state that came from a checkpoint, and the owner’s failure notice says how far the failed run got.
A checkpoint on the run page
A run that records progress as it goes shows it on the run page. The run below swept ACME’s eight regions and checkpointed after each one; had it failed partway, the regions it finished would still be in its state for the next run.

save_state, so its last checkpoint became the saved state, and the run page labels it as a checkpoint rather than as saved state.The administrator’s view
An administrator sees every script and every run on the deployment, on the same pages owners use, with an owner column and two panels the owner view does not need: the busiest scripts and the fires that were missed.

Every run, across every script
The Runs tab is where a missed fire becomes visible, because a fire that did not produce a run has no row anywhere else. Run history is kept for a year, and older history is still reachable one script at a time.

What is settled
Unattended never means unaccountable. A run does what its author could do, is refused what its author could not, cannot reach anything the platform does not mediate, and leaves a record that names the version, the trigger, the outputs, and every call.
Key terms
Nine terms cover the authority and the record of an unattended run.
Key Terms
- Script principalscript:<name>
- The identity a run authenticates as. Audit records it, and the run’s outputs belong to it. It carries the author’s address so the run can act on what the author owns.
- Captured roles
- The roles the author held when the executing version was saved, stored on that version and presented by every run of it. They cannot be set any other way.
- Run gate
- The check that admits or refuses a run. It refuses a script taken out of service (disabled, deprecated, or superseded), in its own words on every surface. A library is never run at all.
- Dry-run account
- The record a dry run leaves of itself: who, when, how it ended, the bounded log, and the shape of the outputs, keyed to the exact source that executed.
- Change summarychange_summary
- The plain-language account of what a new version will do differently, which the person the automation runs for agrees to before a behavior-changing save goes through. It is kept on the version with who saved it and when.
- Test report
- What a version’s tests found at its save: each test’s result, the share of statements reached, and the lines no test reaches.
- Librarylib:<name>@<version>
- A script with no main(), held to the same checks, that other scripts load at a named version. It makes no platform calls, is never run or scheduled, and anyone may load it.
- Checkpointplatform.checkpoint
- State a run stages that the platform commits however the run ends, so progress made before a failure or a time limit is kept.
- Ownership transfer
- An administrator’s move of a script to another person, recorded as a version the administrator authored, after which runs present that administrator’s roles.
