Skip to content
Merged
108 changes: 108 additions & 0 deletions .github/workflows/phase0c-workspace-deep-study-v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Phase 0C Workspace Deep Study V2

on:
pull_request:
paths:
- "design/donors/openai-chatgpt-workspace-deep-study.md"
- "design/candidates/PTAH-WORKSPACE-OPERATIONS-PROFILE-V2.md"
- "design/candidates/workspace-operations-profile-v2.json"
- "design/candidates/workspace-operations-gap-map-v2.json"
- "design/candidates/fixtures/workspace-operations-fixtures-v2.json"
- "tools/check_workspace_operations_donor_v2.py"
- "tools/test_check_workspace_operations_donor_v2.py"
- ".github/workflows/phase0c-workspace-deep-study-v2.yml"
- "design/donors/openai-chatgpt-projects-work.md"
- "design/candidates/ai-project-workspace-profile.json"
- "contracts/generated/catalog-index.json"
Comment on lines +5 to +16

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Align the trigger paths with the validator’s actual inputs.

The validator reads README.md, but this path filter omits it, so a README-only boundary change can merge without rerunning this check. Conversely, design/candidates/PTAH-WORKSPACE-OPERATIONS-PROFILE-V2.md triggers the workflow but is not loaded or hashed by the validator, allowing the human-readable profile to drift from the JSON contract while CI remains green. Add README.md and validate/bind the Markdown profile, or remove the latter from the claimed validation scope.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/phase0c-workspace-deep-study-v2.yml around lines 5 - 16,
Align the workflow path filter with the validator’s actual inputs: add README.md
so README-only changes rerun the check, and either update the validator to load
and hash PTAH-WORKSPACE-OPERATIONS-PROFILE-V2.md or remove that Markdown profile
from the workflow’s paths. Keep the workflow and validator validation scope
consistent.

workflow_dispatch:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Check out exact pull-request head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 1
Comment on lines +26 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/phase0c-workspace-deep-study-v2.yml ]; then
  nl -ba .github/workflows/phase0c-workspace-deep-study-v2.yml | sed -n '1,220p'
else
  echo "workflow not found"
fi

echo "== checkout token references =="
rg -n "github-token|GITHUB_TOKEN|git config|persist-credentials|upload-artifact|artifact|validator-output|github.event.pull_request.head.sha|pull_request|pull_request_target" .github/workflows/phase0c-workspace-deep-study-v2.yml || true

echo "== workflow files mentioning checkout@v4 persist =="
rg -n "actions/checkout@v4|persist-credentials" .github/workflows || true

Repository: jaydumisuni/Ptah-space

Length of output: 220


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/phase0c-workspace-deep-study-v2.yml ]; then
  sed -n '1,220p' .github/workflows/phase0c-workspace-deep-study-v2.yml | awk '{printf "%6d  %s\n", NR, $0}'
else
  echo "workflow not found"
fi

echo "== checkout token references =="
grep -nE "github-token|GITHUB_TOKEN|git config|persist-credentials|upload-artifact|artifact|validator-output|github.event.pull_request.head.sha|pull_request|pull_request_target" .github/workflows/phase0c-workspace-deep-study-v2.yml || true

echo "== workflow files mentioning checkout@v4 persist =="
grep -nE "actions/checkout@v4|persist-credentials" .github/workflows || true

echo "== changed workflow status =="
git diff --stat -- .github/workflows/phase0c-workspace-deep-study-v2.yml || true

Repository: jaydumisuni/Ptah-space

Length of output: 5799


🌐 Web query:

actions/checkout v4 persist-credentials default true GitHub token .git/config

💡 Result:

In actions/checkout v4, the persist-credentials input defaults to true [1][2]. When this setting is enabled, the action configures the Git access token (typically the GITHUB_TOKEN) into the local repository's.git/config file, allowing subsequent steps in your workflow to run authenticated Git commands automatically [3][4][5]. Specifically, in v4, the credential is written directly into the.git/config file as an http.https://github.com/.extraheader value [5]. Because the token is stored within the.git directory, it is included if the workspace (including the.git folder) is uploaded as a build artifact, which creates a potential credential exposure risk [5]. The token is removed by the action during the post-job cleanup phase [3][4]. If your workflow does not require subsequent authenticated Git commands, you can opt out of this behavior by setting persist-credentials to false [3][5]: - uses: actions/checkout@v4 with: persist-credentials: false Setting this to false prevents the credential from being written to the configuration file, thereby reducing the surface area for potential leaks [5].

Citations:


Disable checkout credential persistence before executing PR code.

actions/checkout@v4 persists the workflow token in .git/config by default, and this workflow subsequently runs PR-controlled Python and uploads validator-output.txt, exact-head.txt, exact-head-evidence.json, workspace-deep-study-validation.json, and regressions.txt. A malicious change in the checked-out PR branch can access that token before job cleanup and expose it in logs or artifacts. Set persist-credentials: false; no later authenticated Git operation is needed.

Proposed fix
         with:
           ref: $${{ github.event.pull_request.head.sha || github.sha }}
           fetch-depth: 1
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Check out exact pull-request head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 1
- name: Check out exact pull-request head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 1
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 26-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/phase0c-workspace-deep-study-v2.yml around lines 26 - 30,
Update the actions/checkout@v4 configuration in “Check out exact pull-request
head” to set persist-credentials to false, while preserving the existing ref and
fetch-depth settings.

Source: Linters/SAST tools


- name: Capture exact head
id: head
shell: bash
run: |
set -euo pipefail
HEAD_SHA="$(git rev-parse HEAD)"
EXPECTED_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
test "$HEAD_SHA" = "$EXPECTED_SHA"
echo "sha=$HEAD_SHA" >> "$GITHUB_OUTPUT"
printf '%s\n' "$HEAD_SHA" > exact-head.txt

- name: Run 26 valid and adversarial cases
shell: bash
run: |
set -euo pipefail
python3 tools/test_check_workspace_operations_donor_v2.py -v 2>&1 | tee regressions.txt
Comment on lines +43 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Bind the reported regression count to the executed tests.

The evidence hard-codes regression_case_count: 26, but the workflow never verifies that 26 tests actually ran or that none were skipped. A reduced or skipped suite could still exit successfully and produce false 26/26 evidence. Assert the unittest summary and zero skipped cases, or emit and consume a machine-readable count before writing the evidence file.

Proposed minimum check
           python3 tools/test_check_workspace_operations_donor_v2.py -v 2>&1 | tee regressions.txt
+          grep -Eq '^Ran 26 tests in ' regressions.txt
+          ! grep -Eq '^OK \(skipped=' regressions.txt

Also applies to: 87-89

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/phase0c-workspace-deep-study-v2.yml around lines 43 - 47,
Update the “Run 26 valid and adversarial cases” step and the evidence-generation
step to verify that the executed unittest summary reports exactly 26 tests with
zero skipped cases before recording regression_case_count: 26. Capture and
inspect the test output or emit a machine-readable count, and fail the workflow
when the count or skipped-case condition does not match.


- name: Validate deep Workspace study
shell: bash
run: |
set -euo pipefail
python3 tools/check_workspace_operations_donor_v2.py \
--repo-root . \
--output workspace-deep-study-validation.json \
| tee validator-output.txt

- name: Bind exact-head evidence
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import hashlib
import json
from pathlib import Path

report = json.loads(Path("workspace-deep-study-validation.json").read_text())
if report["status"] != "pass":
raise SystemExit("validation did not pass")
if report["study_method"] != "10 primary + 10 independent verifier lanes":
raise SystemExit("study method mismatch")
if report["mechanical_capability_count"] != 22:
raise SystemExit("mechanical capability count mismatch")
if report["gap_mapping_count"] != 28:
raise SystemExit("gap mapping count mismatch")
if report["fixture_count"] != 20:
raise SystemExit("fixture count mismatch")
for key in ("new_core_entity_required", "frozen_contract_change_required", "runtime_implementation_authorized"):
if report[key] is not False:
raise SystemExit(f"forbidden authority state: {key}")
report_bytes = Path("workspace-deep-study-validation.json").read_bytes()
evidence = {
"schema_version": "0.1.0",
"record_type": "ptah.phase0c.workspace_deep_study_exact_head_evidence",
"head_sha": Path("exact-head.txt").read_text().strip(),
"validation_sha256": hashlib.sha256(report_bytes).hexdigest(),
"regression_case_count": 26,
"primary_lanes": 10,
"independent_verifier_lanes": 10,
"new_core_entity_required": False,
"frozen_contract_change_required": False,
"runtime_implementation_authorized": False,
}
Path("exact-head-evidence.json").write_text(json.dumps(evidence, indent=2, sort_keys=True) + "\n")
PY

- name: Upload retained evidence
uses: actions/upload-artifact@v4
with:
name: phase0c-workspace-deep-study-v2-${{ steps.head.outputs.sha }}
path: |
exact-head.txt
exact-head-evidence.json
workspace-deep-study-validation.json
validator-output.txt
regressions.txt
if-no-files-found: error
retention-days: 90
122 changes: 122 additions & 0 deletions design/candidates/PTAH-WORKSPACE-OPERATIONS-PROFILE-V2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Ptah Workspace Operations Profile V2

Status: candidate, non-operative
Source: deep observable study of the current ChatGPT Workspace plus official public product documentation
Relationship: compatible supplement to the accepted neutral AI Project Workspace profile

## Fixed product boundary

**Ptah is the world and machinery, not the thinker.**

Ptah provides the neutral Workspace and mechanical capabilities needed by humans, Hunter, Sergeant, applications and other agents. It does not choose the job, interpret intent, rank sources, decide truth, approve results, issue a review verdict or choose the next action.

## What this supplement adds

The first AI Project Workspace profile concentrated on the project envelope: chats, files, instructions, project memory, shared work, long-running work, Canvas and schedules.

This supplement studies the deeper operating contract visible in the workspace:

1. typed and incrementally discoverable operation schemas;
2. mechanical effect classes for observe, draft, simulate, mutate, publish, destructive and external-side-effect operations;
3. separation between external Provider permission and local confirmation policy;
4. explicit external-reference, indexed, mounted, materialized and generated-file states;
5. progress Events, failed Attempts and partial Artifact retention;
6. stable handles for results too large for one active Session;
7. replaceable cards, tables, charts and previews as Views;
8. one-off, recurring and condition-dependent schedules with exact or flexible timing semantics;
9. exact Revision and target-head preconditions for safe mutation;
10. distinct succeeded, failed, declined, cancelled, not-run and partially-completed results;
11. staged observe/draft/simulate/execute/verify workflows;
12. source, account and permission provenance for connected systems;
13. stable cross-device and cross-provider continuation;
14. honest product, Provider and execution-limit reporting.

## Operation descriptor

A Facility or Provider operation should expose mechanically inspectable metadata such as:

- operation identity and schema version;
- argument and result schemas;
- effect class;
- required Grant;
- exact supported preconditions;
- expected Receipt states;
- limits and timeout behaviour;
- source Provider and account boundary;
- whether it can be discovered lazily;
- whether it creates or requires materialized bytes.

This is a profile-level contract over existing primitives. It does not create a new Core entity.

## File truth

Ptah must distinguish a reference from bytes it actually holds:

```text
external_reference
→ indexed_reference
→ mounted_read_only or materialized_copy
→ generated_artifact where applicable
```

A connector file reference must never be presented as a local path until an explicit mount or materialization Activity has succeeded and produced a Receipt.

## Action truth

A submitted operation is not proof of its effect.

```text
submitted Activity
→ Attempt
→ Provider response or failure
→ optional independent post-condition verification
→ final Receipt
```

Draft and publish remain separate. Approval and external permission remain separate. Retry creates a new Attempt and preserves the failed Attempt.

## View truth

A message card, table, chart, file preview, mobile record or progress widget is a View over an underlying Object, Artifact, Activity or Receipt.

The View may be replaced without changing the record. A green card cannot accept a candidate. A hidden card cannot erase a failure. Applications may render the same record differently while retaining one identity and provenance chain.

## Scheduling truth

Ptah may mechanically run schedules supplied by a caller:

- one-off;
- recurring;
- condition watch;
- exact time;
- flexible window;
- condition-dependent checks.

Each scheduled Activity receives exact caller-specified Workspace, Recipe, input Revision, Provider and Grant references. It does not inherit hidden context. The caller owns the schedule's purpose and desired outcome.

## Semantic and authority ownership

The following remain outside Ptah:

- intent interpretation;
- job definition;
- context and source selection;
- source trust and authority;
- Provider and tool choice where more than one is compatible;
- semantic worker-output reconciliation;
- approval or rejection;
- result acceptance and canonical promotion;
- next-action choice.

Ptah can execute a submitted search, merge, review or approval workflow. It does not supply the semantic decision.

## Contract conclusion

The deep study found:

- 16 behaviours covered directly by the neutral substrate;
- 6 behaviours composed by caller applications;
- 0 justified Core extensions;
- 6 product behaviours explicitly rejected or not adopted.

No frozen WP01–WP14 contract is reopened. No runtime implementation is authorized. The supplement should be used later as an implementation and conformance profile for Workspace shells, Facility adapters, Activity progress, Artifact delivery and recovery interfaces.
154 changes: 154 additions & 0 deletions design/candidates/fixtures/workspace-operations-fixtures-v2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
{
"schema_version": "0.1.0",
"record_type": "ptah.phase0c.workspace_operations_fixtures_candidate",
"profile_id": "ptah.workspace.operations.v2",
"study_method": {
"primary_lanes": 10,
"independent_verifier_lanes": 10
},
"fixtures": [
{
"id": "lazy-operation-discovery",
"kind": "positive",
"given": "A caller requests GitHub pull-request operations without loading every installed Facility schema.",
"expected": "return_bounded_operation_descriptors",
"proof": ["only matching operation schemas are returned", "schema version and Provider identity are retained", "Ptah does not choose the operation"]
},
{
"id": "effect-class-grant-denial",
"kind": "negative",
"given": "A Grant permits observe operations but a caller submits a destructive operation.",
"expected": "deny_before_execution",
"proof": ["no Attempt with external effect begins", "denial Receipt names the effect class and configured boundary"]
},
{
"id": "external-permission-preservation",
"kind": "positive",
"given": "A connected account can read only a subset of external records.",
"expected": "return_only_provider_permitted_records",
"proof": ["Ptah does not expand external access", "Provider account and scope provenance remain visible"]
},
{
"id": "confirmation-does-not-expand-access",
"kind": "negative",
"given": "A human approves one app action whose external account lacks the requested scope.",
"expected": "external_access_still_denied",
"proof": ["approval does not create Provider permission", "failed effect is retained separately from the approval record"]
},
{
"id": "reference-is-not-materialized-by-name",
"kind": "negative",
"given": "A connector returns a file reference but no bytes have been mounted or copied into the execution Environment.",
"expected": "no_local_path_claim",
"proof": ["availability state remains external_reference", "a separate materialization Activity is required"]
},
{
"id": "materialization-retains-provenance",
"kind": "positive",
"given": "A caller explicitly materializes an external file for a sandboxed Activity.",
"expected": "create_materialized_revision",
"proof": ["source Provider and external identity remain linked", "digest and materialization Receipt are retained"]
},
{
"id": "partial-output-survives-failure",
"kind": "positive",
"given": "A long-running Activity produces two Artifacts and then fails.",
"expected": "retain_failed_attempt_and_partial_artifacts",
"proof": ["failed Attempt remains visible", "partial Artifacts retain lineage", "no success claim is generated"]
},
{
"id": "large-result-resource-handle",
"kind": "positive",
"given": "A Facility returns a result larger than the active Session budget.",
"expected": "retain_stable_handle_and_bounded_access",
"proof": ["result can be paged or searched", "bounded reads cite the same retained result identity"]
},
{
"id": "exact-revision-conflict",
"kind": "negative",
"given": "A write Activity targets Revision A but the Object moved to Revision B before execution.",
"expected": "fail_precondition",
"proof": ["Revision B is not overwritten", "conflict Receipt retains both expected and observed revision identities"]
},
{
"id": "draft-before-publish",
"kind": "positive",
"given": "A caller asks an application to prepare a customer message without sending it.",
"expected": "create_draft_artifact_only",
"proof": ["draft and publish are separate Activities", "no external-side-effect Receipt exists"]
},
{
"id": "invocation-is-not-success",
"kind": "negative",
"given": "A tool call was submitted but the Provider returned no completion response.",
"expected": "not_run_or_unknown_effect_not_success",
"proof": ["no succeeded Receipt is fabricated", "verification may be requested as a separate Activity"]
},
{
"id": "declined-failed-cancelled-distinction",
"kind": "positive",
"given": "Three Attempts respectively receive human denial, Provider failure and caller cancellation.",
"expected": "three_distinct_result_states",
"proof": ["declined, failed and cancelled remain distinguishable", "none is rewritten as successful"]
},
{
"id": "render-independent-view",
"kind": "positive",
"given": "One Receipt is displayed as a chat card, table and mobile summary.",
"expected": "same_underlying_receipt",
"proof": ["all Views cite the same record identity", "removing one View does not remove the Receipt"]
},
{
"id": "view-cannot-promote-authority",
"kind": "negative",
"given": "A UI card labels a candidate green while the underlying acceptance record remains pending.",
"expected": "underlying_state_remains_pending",
"proof": ["View styling creates no acceptance record", "caller must issue the authority decision"]
},
{
"id": "condition-watch-no-notification",
"kind": "positive",
"given": "A condition-triggered Activity checks its source and the configured condition is false.",
"expected": "retain_check_without_user_notification",
"proof": ["check Attempt is retained", "no notification Artifact is emitted"]
},
{
"id": "scheduled-task-exact-input-boundary",
"kind": "negative",
"given": "A scheduled Activity requests a Workspace file that was not supplied in its immutable input set.",
"expected": "deny_unconfigured_input",
"proof": ["schedule does not inherit hidden Session context", "missing input is reported"]
},
{
"id": "cross-device-resume",
"kind": "positive",
"given": "A Session created on mobile is resumed through a desktop application using the same Workspace records.",
"expected": "resume_same_session_and_artifacts",
"proof": ["stable identities survive UI replacement", "Provider and device changes create no authority change"]
},
{
"id": "semantic-merge-remains-caller-owned",
"kind": "negative",
"given": "Two independent workers return conflicting conclusions.",
"expected": "retain_both_without_ptah_verdict",
"proof": ["Ptah may execute a caller-supplied merge Recipe", "Ptah does not decide which conclusion is correct"]
},
{
"id": "resource-limit-is-visible",
"kind": "positive",
"given": "An Activity exceeds its configured execution or product limit.",
"expected": "retain_limit_receipt",
"proof": ["limit class and measured value are reported", "Ptah does not silently reduce semantic scope"]
},
{
"id": "retry-preserves-prior-attempt",
"kind": "negative",
"given": "A configured retry begins after a failed Attempt.",
"expected": "new_attempt_without_erasure",
"proof": ["failed Attempt remains retained", "retry has a new identity and links to its predecessor"]
}
],
"new_core_entity_required": false,
"frozen_contract_change_required": false,
"runtime_implementation_authorized": false
}
Loading
Loading