Compare commits
20 Commits
project-2_
...
project-2
| Author | SHA1 | Date | |
|---|---|---|---|
| cd9dd574d9 | |||
| e5e4900a1c | |||
| dc32054619 | |||
| 2d2c5af37d | |||
| 6890b48937 | |||
| 19e71875b1 | |||
| e9ff5974a8 | |||
| 56ecfb465a | |||
| 9d850a3f3b | |||
| 68c9cf39d9 | |||
| f9bec5de44 | |||
| 9cb80f557b | |||
| 81a67ddf16 | |||
| c6b5d7d9c2 | |||
| 84441dbfb7 | |||
| 54e0efa068 | |||
| 40dfd6252d | |||
| f29b77bcab | |||
| ebd3474db3 | |||
| e814569a07 |
65
sources/holistic-rubric-new.md
Normal file
65
sources/holistic-rubric-new.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Holistic Rubric: Multi-Tenant Authorization in Background Workers
|
||||||
|
|
||||||
|
### Task Summary
|
||||||
|
The goal is to audit and refactor background SQS worker handlers (`voice-synthsizer-job-handler` and `voice-cloning-job-handler`) and database service wrappers in `potion-voice` to enforce strict multi-tenant data isolation by scoping all MongoDB queries with `userId`. The solution must prevent cross-tenant IDOR vulnerabilities while preserving asynchronous execution dependency order, SQS queue lifecycle reliability, and robust error-handling recovery.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ground Truth
|
||||||
|
1. **Queue Message Context**: SQS messages for voice synthesis contain `job.salutationId`, `job.userAudioProfileId`, and `job.userId`, but do **not** convey `job.recordingId`.
|
||||||
|
2. **Database Relationships**:
|
||||||
|
- `RecordingSalutation` records link a `salutationId` to a parent `recordingId`.
|
||||||
|
- `recordingId` must be extracted from `salutationToUpdate.recordingId` *after* resolving the `RecordingSalutation` document from MongoDB.
|
||||||
|
3. **Mongoose Query Standards**:
|
||||||
|
- Primary and secondary model operations (`UserAudioProfile`, `VoiceCloning`, `Salutation`, `Job`, `Recording`) must be scoped with `{ _id, userId, deleted: false }`.
|
||||||
|
- Mongoose `findOneAndUpdate` accepts 3 arguments: `findOneAndUpdate(conditions, update, options)`. Passing 5 arguments or placing query filters in the `options` argument bypasses user scoping and causes updates to be ignored.
|
||||||
|
4. **Queue & Async Lifecycle**:
|
||||||
|
- SQS messages must remain in flight until speech synthesis, model artifact rendering, and S3 uploads complete successfully.
|
||||||
|
- Deleting messages via `sqs.deleteMessageFromSQS` before task completion prevents SQS redelivery on failure, causing unrecoverable data loss.
|
||||||
|
5. **Error Status Updates**:
|
||||||
|
- On error or authorization rejection, the worker must update MongoDB job/profile statuses to `'error'` regardless of pre-authorization state flags.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Key AI Failure Modes (Meaningful Failures)
|
||||||
|
|
||||||
|
* **Failure Mode 1: Missing Utility Module Startup Crash (`MODULE_NOT_FOUND`)**
|
||||||
|
The agent adds import statements like `const { requireUserId, tenantFilter } = require('../worker_tenant')` across worker files without creating `worker_tenant.js` or `worker_tenant/index.js` in the repository. At runtime, Node.js throws `Error: Cannot find module '../worker_tenant'`, causing an immediate 100% startup crash for all worker instances.
|
||||||
|
|
||||||
|
* **Failure Mode 2: Premature SQS Queue Message Deletion (Silent Data Loss)**
|
||||||
|
The agent relocates `sqs.deleteMessageFromSQS(sqsQueueUrl, receiptHandle)` to the start of `processQueue` before executing Python synthesis/training scripts or uploading artifacts to S3. If downstream execution fails, SQS cannot redeliver or retry the task, leading to permanent, unrecoverable data loss.
|
||||||
|
|
||||||
|
* **Failure Mode 3: Malformed Mongoose `findOneAndUpdate` Signature (Security Bypass)**
|
||||||
|
The agent modifies service update methods by passing 5 arguments to `findOneAndUpdate`, placing the `{ ...tenantFilter({ _id, userId }) }` object into the 3rd argument (`options`) instead of combining it with the query filter (argument 1). Consequently, the query remains unscoped (`{ _id: data._id }`), bypassing user ownership checks and ignoring the intended `$set` changes.
|
||||||
|
|
||||||
|
* **Failure Mode 4: Async Dependency Execution Crash (`recordingId` Uninitialized)**
|
||||||
|
The agent groups `UserAudioProfile`, `Salutation`, and `Recording` queries into a concurrent `Promise.all` block. Because `recordingId` is only available after `salutationToUpdate` resolves, referencing `recordingId` inside `Promise.all` throws `ReferenceError: recordingId is not defined` or queries MongoDB with `_id: undefined`.
|
||||||
|
|
||||||
|
* **Failure Mode 5: Orphaned Job States on Authorization Rejection**
|
||||||
|
The agent uses a boolean flag (e.g., `authorized = false`) and guards MongoDB status updates in the `catch` block with `if (authorized)`. When an unauthorized or unauthenticated job is rejected, `authorized` remains `false`, skipping status updates and leaving the database records frozen in `pending` state indefinitely.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Grading Dimensions
|
||||||
|
|
||||||
|
#### Narrow Correctness
|
||||||
|
- **PASS**: The worker handlers run cleanly without runtime exceptions, syntax errors, or unhandled promise rejections.
|
||||||
|
- **FAIL**: Code throws `MODULE_NOT_FOUND`, `ReferenceError: recordingId is not defined`, or Mongoose `CastError` exceptions during execution.
|
||||||
|
|
||||||
|
#### Broader Correctness
|
||||||
|
- **PASS**: All primary and secondary MongoDB queries and updates enforce `userId` scoping, preventing cross-tenant access. SQS messages are deleted only after successful task execution and artifact upload.
|
||||||
|
- **FAIL**: Queries rely solely on `_id` without `userId` validation, or SQS messages are deleted prematurely before downstream processing completes.
|
||||||
|
|
||||||
|
#### Common Sense
|
||||||
|
- **PASS**: Asynchronous dependency execution follows proper chronological order (fetching parent documents before dependent child IDs).
|
||||||
|
- **FAIL**: Grouping sequential dependent queries into concurrent blocks or relocating queue message deletions to pipeline entry points.
|
||||||
|
|
||||||
|
#### Verification & Thoroughness
|
||||||
|
- **PASS**: The worker pipeline behavior and database error transitions are verified against expected queue message schemas.
|
||||||
|
- **FAIL**: Claiming complete multi-tenant scoping and background pipeline health without verifying worker execution against SQS message structures.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Scoring Guide
|
||||||
|
* **PASS (1.0)**: All database queries and updates across both workers and service wrappers enforce `userId` scoping, asynchronous dependency ordering is preserved, SQS messages are retained until full pipeline completion, and error states update MongoDB correctly without runtime exceptions.
|
||||||
|
* **FAIL (0.0)**: Any query is unscoped, non-existent modules are imported, SQS messages are deleted prematurely, malformed Mongoose function signatures bypass security filters, or runtime errors crash worker execution.
|
||||||
@@ -1,19 +1,9 @@
|
|||||||
Key Meaningful Failures Identified in code-diff.txt
|
The first meaningful failure involves a missing utility module causing startup crashes. In several files including voice-cloning-job-handler/index.js, voice-synthsizer-job-handler/index.js, user_audio_profile_service.js, and voice_cloning_service.js, the AI added import statements for a utility called 'worker_tenant' with lines like 'const { requireUserId, tenantFilter } = require('../worker_tenant')'. However, the AI never created the worker_tenant.js file anywhere in the repository. This results in Node.js throwing an 'Error: Cannot find module' when background workers start, causing an immediate 100% startup crash for all queue workers in production.
|
||||||
|
|
||||||
1. Missing Utility Module (MODULE_NOT_FOUND Startup Crash)
|
The second meaningful failure is premature SQS message deletion leading to permanent silent data loss. In voice-cloning-job-handler/index.js, the AI moved the SQS deletion call to the very top of the processQueue function, before checking the user ID, before validating tenant records, and before running the ML tasks and uploading model artifacts. This violates SQS queue reliability standards because messages should only be deleted after the job succeeds. If the job fails after the message is deleted, the message cannot be recovered or retried, leading to permanent and silent data loss without any trace or retry capability.
|
||||||
The AI added imports for a utility module called worker-tenant in several files, but that module does not exist in the repository. When the Node.js worker processes start, they crash with an error saying they cannot find the module. This causes both queue handlers to fail immediately in production.
|
|
||||||
|
|
||||||
2. Premature SQS Queue Message Deletion (Permanent Data Loss)
|
The third meaningful failure is a malformed Mongoose findOneAndUpdate signature that bypasses user scoping. In user_audio_profile_service.js, voice_cloning_service.js, and salutation_service.js, the AI passed five arguments to Mongoose's findOneAndUpdate function, but the function only accepts three arguments. The AI placed the tenant filter in the wrong argument position, so the query was not scoped by user ID and the update operation was ignored. This creates two serious problems: first, a security bypass where the update operation could modify any user's data because it was not checking the user ID; second, corrupted updates where the intended changes were not applied because the update argument was ignored by Mongoose.
|
||||||
In the voice cloning job handler, the code deletes the SQS message at the beginning of processing, before any work is done. SQS expects messages to stay in the queue until processing finishes successfully. If something goes wrong later, the message is already gone and cannot be retried, leading to silent loss of jobs.
|
|
||||||
|
|
||||||
3. Broken Error Recovery and Orphaned Job States
|
The fourth meaningful failure is orphaned job states on authorization failure. In voice-cloning-job-handler/index.js, the AI added a flag to track authorization. If the job was not authorized, the flag remained false and the error handling block did not update the database. When an unauthorized job fails, the system does not update the job status in the database, leaving the job stuck in a pending state indefinitely. Unauthorized or failing jobs remain in the database indefinitely, providing no feedback to users or system operators about what went wrong.
|
||||||
When a document authorization check fails, the handler throws an error before marking the job as authorized. The error handling code only updates the database if the authorized flag is true. Because the flag stays false, the database never gets updated, and the job remains stuck in a pending state forever.
|
|
||||||
|
|
||||||
Evaluation Against Raccoon Failure Criteria
|
These failures satisfy the this project's failure criteria in several ways. Senior engineers would universally agree that missing files, premature queue deletions, and incorrect function usage constitute critical defects worth blocking a pull request. These mistakes highlight essential lessons in dependency management, queue handling semantics, and proper database API usage that are valuable for engineering feedback. Any lead engineer would block a PR containing startup crashes and silent data loss as these issues are serious enough to halt deployment. Most importantly, these defects have real-world consequences including production worker pipeline outages, permanent data loss, and potential security vulnerabilities that could compromise user data integrity.
|
||||||
According to the Raccoon task criteria, a mistake is a meaningful failure when it meets four requirements:
|
|
||||||
- Most senior engineers would agree that importing missing modules and deleting queue messages too early are serious bugs.
|
|
||||||
- A teammate would give direct feedback about queue handling and missing files.
|
|
||||||
- Both issues are bad enough to block a pull request.
|
|
||||||
- The code causes real problems: worker processes crash and queue data is lost permanently in production.
|
|
||||||
|
|
||||||
These problems give a solid basis for building a reproducible Raccoon benchmark task.
|
|
||||||
@@ -1,43 +1,66 @@
|
|||||||
|
Yes, **meaningful failures definitely occurred** in `code-diff.txt`.
|
||||||
|
|
||||||
### Key Meaningful Failures Identified in `code-diff.txt`
|
While the prompt in `instruction.md` instructed the AI to enforce strict user ownership checks across background worker database queries, the diff generated in `code-diff.txt` introduced several severe runtime, architectural, and security defects.
|
||||||
|
|
||||||
#### 1. Missing Utility Module (`MODULE_NOT_FOUND` Startup Crash)
|
Here is a breakdown of the specific meaningful failures identified in `code-diff.txt`:
|
||||||
* **What the AI did**: Across multiple files (`voice-cloning-job-handler/index.js`, `voice-synthsizer-job-handler/index.js`, and model service wrappers), the generated code added imports for a new utility module:
|
|
||||||
`const { requireUserId, requireDocumentId } = require('../worker-tenant')`.
|
|
||||||
* **The Flaw**: The git diff does not create or include `worker-tenant.js` or any `worker-tenant` directory anywhere in the repository.
|
|
||||||
* **Real-World Consequence**: When Node.js starts either background worker process, it immediately throws `Error: Cannot find module '../worker-tenant'`, causing an **instant, 100% startup crash** for both queue handlers in production.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 2. Premature SQS Queue Message Deletion (Permanent Data Loss)
|
### 1. Missing Utility Module (`MODULE_NOT_FOUND` Startup Crash)
|
||||||
* **What the AI did**: In `voice-cloning-job-handler/index.js`, the code relocated the SQS deletion call:
|
* **What the AI did**: Across multiple files—including `voice-cloning-job-handler/index.js`, `voice-synthsizer-job-handler/index.js`, and model service files like `user_audio_profile_service.js` and `voice_cloning_service.js`—the generated diff adds imports for a new tenant utility:
|
||||||
`await sqs.deleteMessageFromSQS(sqsQueueUrl, receiptHandle)`
|
```javascript
|
||||||
to the top of `processQueue`, executing **before** validating tenant documents, running heavy Python machine learning scripts (`prepare_datasets.py`, `clone_voice.py`), or uploading model artifacts to S3.
|
const { requireUserId, tenantFilter } = require('../worker_tenant') // or ../../worker_tenant
|
||||||
* **The Flaw**: SQS queue semantics require messages to remain in flight until processing completes successfully.
|
```
|
||||||
* **Real-World Consequence**: If any downstream step fails (e.g., Python ML process crash, EFS disk write error, or S3 network timeout), the job jumps to the `catch` block. Because the SQS message was already deleted, the queue cannot redeliver or retry the task, leading to **permanent, silent job loss**.
|
* **The Flaw**: The diff **never creates `worker_tenant.js`** anywhere in the repository.
|
||||||
|
* **Real-World Consequence**: When Node.js boots either background worker process, it immediately throws `Error: Cannot find module '../worker_tenant'`, causing an **instant 100% startup crash** for all queue workers in production.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 3. Broken Error Recovery and Orphaned Job States
|
### 2. Premature SQS Message Deletion (Permanent Silent Data Loss)
|
||||||
* **What the AI did**: In `voice-cloning-job-handler/index.js`, if a document authorization check fails, the handler throws an error before setting `authorized = true`.
|
* **What the AI did**: In `voice-cloning-job-handler/index.js`, the AI moved the SQS deletion call:
|
||||||
* **The Flaw**: Inside the `catch (error)` block, database error updates are guarded by `if (authorized)`:
|
```javascript
|
||||||
|
await sqs.deleteMessageFromSQS(sqsQueueUrl, receiptHandle)
|
||||||
|
```
|
||||||
|
to the very top of `processQueue` inside the `try` block—executing **before** checking `requireUserId(userId)`, before validating tenant records in MongoDB, and before running dataset preparation (`prepare_datasets.py`), voice cloning (`clone_voice.py`), or S3 model artifact uploads.
|
||||||
|
* **The Flaw**: Violates SQS queue reliability standards. SQS messages must only be deleted after job execution and artifact storage succeed.
|
||||||
|
* **Real-World Consequence**: If authorization fails, or if Python ML/S3 tasks crash midway, the SQS message has already been deleted. The queue cannot redeliver or retry the job, causing **permanent, silent data loss** without trace or retry capability.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Malformed Mongoose `findOneAndUpdate` Signature (Bypassed User Scoping)
|
||||||
|
* **What the AI did**: In `user_audio_profile_service.js`, `voice_cloning_service.js`, and `salutation_service.js`, the AI modified `update()` to pass **5 arguments** to Mongoose's `findOneAndUpdate`:
|
||||||
|
```javascript
|
||||||
|
const updatedModel = await UserAudioProfileModel.findOneAndUpdate(
|
||||||
|
{ _id: data._id }, // Arg 1: Query conditions
|
||||||
|
data, // Arg 2: Update document
|
||||||
|
{ ...tenantFilter({ _id, userId }), deleted: false },// Arg 3: Options (tenant filter placed here!)
|
||||||
|
{ $set: changes }, // Arg 4: Ignored by Mongoose
|
||||||
|
{ new: true } // Arg 5: Ignored by Mongoose
|
||||||
|
)
|
||||||
|
```
|
||||||
|
* **The Flaw**: Mongoose's `findOneAndUpdate(conditions, update, options)` only takes 3 arguments. The AI placed the `tenantFilter` inside the 3rd argument (options) instead of combining it with the query filter (arg 1).
|
||||||
|
* **Real-World Consequence**:
|
||||||
|
1. **Security Bypass**: The query filter remains `{ _id: data._id }` (unscoped by `userId`), completely bypassing the user ownership requirement during updates.
|
||||||
|
2. **Corrupted Updates**: The actual update operation `{ $set: changes }` is pushed to arg 4, which Mongoose ignores entirely.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Orphaned Job States on Authorization Failure
|
||||||
|
* **What the AI did**: In `voice-cloning-job-handler/index.js`, the AI introduced an `authorized = false` flag. If `requireUserId(userId)` fails or document ownership checks fail, an error is thrown before `authorized = true`. Inside `catch (error)`, database error updates are wrapped in `if (authorized)`:
|
||||||
```javascript
|
```javascript
|
||||||
if (authorized) {
|
if (authorized) {
|
||||||
await voiceCloningService.update({ _id, userId, status: 'error' })
|
await voiceCloningService.update({ _id, userId, status: 'error' })
|
||||||
await userAudioProfileService.update({ _id: userAudioProfileId, userId, status: 'error' })
|
await userAudioProfileService.update({ _id: userAudioProfileId, userId, status: 'error' })
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* **Real-World Consequence**: When an unauthorized job is rejected, `authorized` remains `false`. The error handler skips updating MongoDB, leaving the database records stuck in their previous pending states indefinitely.
|
* **The Flaw**: When an unauthorized job is rejected, `authorized` remains `false`, so the `catch` block skips updating MongoDB.
|
||||||
|
* **Real-World Consequence**: Unauthorized or failing jobs are left stuck in their initial pending state in MongoDB indefinitely, providing no feedback to users or system operators.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Evaluation Against Raccoon Failure Criteria
|
### How This Satisfies the Raccoon Failure Criteria
|
||||||
|
|
||||||
According to the Raccoon task criteria, a mistake is classified as a **meaningful failure** when it satisfies four requirements:
|
1. **Broad Agreement**: Senior engineers would universally agree that uncreated imports, premature queue deletions, and invalid Mongoose function signatures are critical code defects.
|
||||||
|
2. **Feedback Worth Giving**: These mistakes highlight essential lessons in async control flow, SQS queue lifecycle semantics, and Mongoose API usage.
|
||||||
1. **Broad Agreement**: Over 80% of senior software engineers would agree that importing non-existent modules and deleting queue messages prior to job execution are critical defects.
|
3. **Serious Enough to Block**: Any lead engineer would block a PR containing startup crashes and silent queue message deletions.
|
||||||
2. **Feedback Worth Giving**: A team member would receive direct corrective feedback regarding queue lifecycle semantics and missing file dependencies.
|
4. **Real Consequence**: Production worker pipeline outages, data loss, and security bypasses.
|
||||||
3. **Serious Enough to Block**: Both issues represent immediate pull-request blockers.
|
|
||||||
4. **Real Consequence**: The code results in complete worker process crashes and unrecoverable queue data loss in production.
|
|
||||||
|
|
||||||
These verified failures provide a solid foundation for constructing a reproducible Raccoon benchmark task.
|
|
||||||
17
sources/restart-process-steps.ms
Normal file
17
sources/restart-process-steps.ms
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
In Project
|
||||||
|
|
||||||
|
cp worker .env .. (-t [unclear] DA) ../env
|
||||||
|
|
||||||
|
cp worker /repos/.gitignore ../gitignore
|
||||||
|
|
||||||
|
Wipe away worker-toolkit —
|
||||||
|
|
||||||
|
unzip polyglot toolkit
|
||||||
|
|
||||||
|
mv worker-toolkit to
|
||||||
|
sudo chown -R "$USER":"$USER" .
|
||||||
|
|
||||||
|
Rename toolkit
|
||||||
|
mv env to worker-toolkit.../.env
|
||||||
|
mv gitignore to worker-toolkit.../repos/.gitignore
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ volume, and none of those name a person or a checkout.
|
|||||||
```bash
|
```bash
|
||||||
# Absolute home-rooted paths that continue into a checkout, on added lines:
|
# Absolute home-rooted paths that continue into a checkout, on added lines:
|
||||||
grep -E '^\+' environment/workspace.patch | grep -vE '^\+\+\+' \
|
grep -E '^\+' environment/workspace.patch | grep -vE '^\+\+\+' \
|
||||||
| grep -nE '(/home/[a-zA-Z][^/[:space:]"'"'"']*|/Users/[a-zA-Z][^/[:space:]"'"'"']*|/mnt/[a-z]/[a-zA-Z][^/[:space:]"'"'"']*)(/[^/[:space:]"'"'"']+)*/(worker-toolkit-[a-z0-9-]+|Toolkits|repo)/'
|
| grep -nE '(/home/[a-zA-Z][^/[:space:]"'"'"']*|/Users/[a-zA-Z][^/[:space:]"'"'"']*|/mnt/[a-z]/[a-zA-Z][^/[:space:]"'"'"']*)(/[^/[:space:]"'"'"']+)*/(worker-toolkit-[a-z0-9.-]+|Toolkits|repo)/'
|
||||||
```
|
```
|
||||||
|
|
||||||
A hit is an `internal-leak`. Across the corpus this fires on 2 of 350 patches,
|
A hit is an `internal-leak`. Across the corpus this fires on 2 of 350 patches,
|
||||||
@@ -172,8 +172,8 @@ To grade under the atomic rubric inside the worker toolkit, stage the grading
|
|||||||
copies with `npx tsx scripts/stage-atomic-rubric.ts <task-slug>`. Staging renders
|
copies with `npx tsx scripts/stage-atomic-rubric.ts <task-slug>`. Staging renders
|
||||||
the criteria file the grader reads, writes the criteria metadata the score renderer
|
the criteria file the grader reads, writes the criteria metadata the score renderer
|
||||||
reads, and syncs `tests/render-rubric-grade.py` from `task-shared/`. Re-run it
|
reads, and syncs `tests/render-rubric-grade.py` from `task-shared/`. Re-run it
|
||||||
after every rubric edit. Staged files are derived from the rubric; run the script
|
after every rubric edit. Staged files are derived from the rubric; `submit-task`
|
||||||
with `--restore` to remove them before packaging the task.
|
leaves them out of the package.
|
||||||
|
|
||||||
To grade under the atomic rubric, stage the grading copies with
|
To grade under the atomic rubric, stage the grading copies with
|
||||||
`npx tsx scripts/stage-atomic-rubric.ts <task-slug>` inside the devcontainer: staging
|
`npx tsx scripts/stage-atomic-rubric.ts <task-slug>` inside the devcontainer: staging
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"args": {
|
"args": {
|
||||||
"TOOLKIT_BUILD_ID": "1790712369311-8xr6mu"
|
"TOOLKIT_BUILD_ID": "1791247286386-y2uh1u"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
|
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
|
||||||
@@ -123,8 +123,8 @@ bash scripts/welcome.sh authoring 2>/dev/null
|
|||||||
|
|
||||||
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
||||||
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
||||||
_WID="w-mun3wr6n-v83f"
|
_WID="w-muvydvub-qn4j"
|
||||||
_VER="1.0.0"
|
_VER="1.0.1"
|
||||||
_CT="authoring"
|
_CT="authoring"
|
||||||
_RP=$(node -e "try{process.stdout.write(require('$PWD/toolkit.json').repo)}catch{}" 2>/dev/null)
|
_RP=$(node -e "try{process.stdout.write(require('$PWD/toolkit.json').repo)}catch{}" 2>/dev/null)
|
||||||
_SID="$(date +%s)-$$"
|
_SID="$(date +%s)-$$"
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"generatedAt": "2026-09-29T20:06:24.470Z",
|
"generatedAt": "2026-10-06T00:41:40.489Z",
|
||||||
"files": {
|
"files": {
|
||||||
"scripts/atif_session.py": "9984fd180d08c2eaecf752cc5accfbf874396396cdcf599f69259b5127f90859",
|
"scripts/atif_session.py": "9984fd180d08c2eaecf752cc5accfbf874396396cdcf599f69259b5127f90859",
|
||||||
"scripts/browser_note.py": "7ee1485c459e76b47ff03a672357ae2d0910890cdc9fdb816a53c56977ff2985",
|
"scripts/browser_note.py": "7ee1485c459e76b47ff03a672357ae2d0910890cdc9fdb816a53c56977ff2985",
|
||||||
"scripts/build-workspace.sh": "e40cebbcad520aaeea2a3c0352bae880dd779011e92926de66d9132514041c2a",
|
"scripts/build-workspace.sh": "0792690e1c28acd8d2902134504158a18a0f4bf4671d6e8733a09bfb8a1440a5",
|
||||||
"scripts/check-task-infra.ts": "678dfb26b11d1fcd2c48345708262fb2c2d5ba0057fb96eabc072eed10fdb4cf",
|
"scripts/check-task-infra.ts": "678dfb26b11d1fcd2c48345708262fb2c2d5ba0057fb96eabc072eed10fdb4cf",
|
||||||
"scripts/check-workspace-sync.sh": "14a6e877ff51f8b86e5e1e32f0ed3143f9e718793b20640b51060eacbbf2f9d4",
|
"scripts/check-workspace-sync.sh": "14a6e877ff51f8b86e5e1e32f0ed3143f9e718793b20640b51060eacbbf2f9d4",
|
||||||
"scripts/codex_agent.py": "87e1df907bea2b1c56b032c0848f0108c948cdf63a5a0682255b7d702aacc6be",
|
"scripts/codex_agent.py": "7953d0b511843591c7ed82d8a2316c52ed79c4cf948dd42fba7d094bb5f4857a",
|
||||||
"scripts/codex-rollout-template.jsonl": "9026ef83466a5c657dc88faaf2ebf0bad93ff865afe4531e9b78465eb99504d1",
|
"scripts/codex-rollout-template.jsonl": "9026ef83466a5c657dc88faaf2ebf0bad93ff865afe4531e9b78465eb99504d1",
|
||||||
"scripts/copy-reference-run.ts": "260a970f9165d3e35013232a4e364c07827e0c04db995bc3dc14aa4b545244b8",
|
"scripts/copy-reference-run.ts": "260a970f9165d3e35013232a4e364c07827e0c04db995bc3dc14aa4b545244b8",
|
||||||
"scripts/dnsjail.py": "d814f1103860ac34f4ed191edd5a6e19580c9d1519cb1c51aaaf53cf709cbc0e",
|
"scripts/dnsjail.py": "d814f1103860ac34f4ed191edd5a6e19580c9d1519cb1c51aaaf53cf709cbc0e",
|
||||||
"scripts/guidance-target.sh": "edcb5b497206911ffdfef432629ea7afc229aac641700166209ad68d22f04a2d",
|
"scripts/guidance-target.sh": "edcb5b497206911ffdfef432629ea7afc229aac641700166209ad68d22f04a2d",
|
||||||
"scripts/harbor-regrade": "c3c67fc339fc9264bf85234d3fc15116467be79f841a3bdaed76716c4a358305",
|
"scripts/harbor-regrade": "a9ff2ae923324dd422cb51c9576536850f900bf8af577637ec6adfbcbca9f6f5",
|
||||||
"scripts/harbor-run": "0ee5f6b1e9a7ca4b872faba0431c3868840a9a5d466bf7aab21bd39455cf6bdd",
|
"scripts/harbor-run": "ec98b793179554e874c86655841744f7c61486a8a5e40bb293130258b8f2cb58",
|
||||||
"scripts/harness-registry.toml": "ebe2c2002c35499a6c03dc0bed46c64e90e9d27aee8e33cb35aca74c925388e7",
|
"scripts/harness-registry.toml": "ebe2c2002c35499a6c03dc0bed46c64e90e9d27aee8e33cb35aca74c925388e7",
|
||||||
"scripts/harness-session.d.mts": "73223ab9fd003e2e299e0e46a02ee0be00d7541a2fcf803b871195688d4b8109",
|
"scripts/harness-session.d.mts": "73223ab9fd003e2e299e0e46a02ee0be00d7541a2fcf803b871195688d4b8109",
|
||||||
"scripts/harness-session.mjs": "ca4d6dc835453b207511275775a71383bb1358a64ba7257877592f8616b2118f",
|
"scripts/harness-session.mjs": "ca4d6dc835453b207511275775a71383bb1358a64ba7257877592f8616b2118f",
|
||||||
@@ -29,8 +29,10 @@
|
|||||||
"scripts/lib/notice-banner.ts": "6a35e92600a9f3ac46c49197eef44d49705f7a5205d1f14f3a20b65bc9cf19b7",
|
"scripts/lib/notice-banner.ts": "6a35e92600a9f3ac46c49197eef44d49705f7a5205d1f14f3a20b65bc9cf19b7",
|
||||||
"scripts/lib/patch-size.ts": "9f5da242c6eafc510e9b95ae5764074eca3b287858b83f087aeb4a47972b4089",
|
"scripts/lib/patch-size.ts": "9f5da242c6eafc510e9b95ae5764074eca3b287858b83f087aeb4a47972b4089",
|
||||||
"scripts/lib/resolve-pin.sh": "00883384bc26aafdf2c2cc9884d1768560301689d493ac1ba276e8618dc72901",
|
"scripts/lib/resolve-pin.sh": "00883384bc26aafdf2c2cc9884d1768560301689d493ac1ba276e8618dc72901",
|
||||||
"scripts/lib/task-infra-integrity.ts": "9749de98356a3eb435dd6386266b6560785378bcb930c306d11ff22ef93feb70",
|
"scripts/lib/secret-scrub.test.ts": "f4e96cf8b2de74af845fa8c2dc3dff16d3fe11a0be41caa47d3cc124149a22dd",
|
||||||
"scripts/lib/toolkit-script-integrity.ts": "6b88e40832d268c15af6568acc97c877210169d73ee31e50903e8e1e936dbb16",
|
"scripts/lib/secret-scrub.ts": "0a174a42cb32c0909fd91b0ff7ca3d8009dfc8fa302549f2edd5468f46f28f0a",
|
||||||
|
"scripts/lib/task-infra-integrity.ts": "5936c14ffab215076921df753c6c0da12ba19125d389edc7362970463bacde90",
|
||||||
|
"scripts/lib/toolkit-script-integrity.ts": "5fd5b9ce493e292e402732726d1418b36dd7640209d05255953fbfa835244ea5",
|
||||||
"scripts/lib/tree-permissions.test.ts": "31692facc68a3c7930655626374c48de8be1ed11d97242eb74538df2a80f2a35",
|
"scripts/lib/tree-permissions.test.ts": "31692facc68a3c7930655626374c48de8be1ed11d97242eb74538df2a80f2a35",
|
||||||
"scripts/lib/tree-permissions.ts": "06e9934fe0937e430071b1a33653f8682193e90078908740512f7e06475e94ec",
|
"scripts/lib/tree-permissions.ts": "06e9934fe0937e430071b1a33653f8682193e90078908740512f7e06475e94ec",
|
||||||
"scripts/record-detector-inputs.ts": "b22245dafa74cc7ad6376cffb4eafc349e39efb94dc71e025550abab033b68e9",
|
"scripts/record-detector-inputs.ts": "b22245dafa74cc7ad6376cffb4eafc349e39efb94dc71e025550abab033b68e9",
|
||||||
@@ -38,11 +40,11 @@
|
|||||||
"scripts/refresh-harness-auth": "b056eb1ec092a7fb3dde549ac3d353abc141cb32367f6b484fc9f879e99733fd",
|
"scripts/refresh-harness-auth": "b056eb1ec092a7fb3dde549ac3d353abc141cb32367f6b484fc9f879e99733fd",
|
||||||
"scripts/replay_agent.py": "feeea82daa555e3203cb131bbb002c4e6f0d7d492570bfd657cfc22b9fc40cde",
|
"scripts/replay_agent.py": "feeea82daa555e3203cb131bbb002c4e6f0d7d492570bfd657cfc22b9fc40cde",
|
||||||
"scripts/resolve_harness.py": "06e1529431db040dab776aad34e1b8c6af4f29172bca5dd93c040f7d9b6f6547",
|
"scripts/resolve_harness.py": "06e1529431db040dab776aad34e1b8c6af4f29172bca5dd93c040f7d9b6f6547",
|
||||||
"scripts/sanitize-session-jsonl.ts": "6bbe28d70c4366f96758cdda366549ec37e1d069020066ba608f72f7e239a218",
|
"scripts/sanitize-session-jsonl.ts": "3aa9d0c696cf999c56adac7a359e4a842afa7c8898e95176772caaff13f47d5a",
|
||||||
"scripts/session-id.ts": "bb21a90a235785fd69296b05c47fa4bb081abce6d254e5a9ad65d19016dbc421",
|
"scripts/session-id.ts": "bb21a90a235785fd69296b05c47fa4bb081abce6d254e5a9ad65d19016dbc421",
|
||||||
"scripts/setup-harnesses.sh": "39f6ca5cfa795d2d621dfa48287545486f060cfeae34c9e2b9ae6921d7275ea4",
|
"scripts/setup-harnesses.sh": "39f6ca5cfa795d2d621dfa48287545486f060cfeae34c9e2b9ae6921d7275ea4",
|
||||||
"scripts/snapshot_agent.py": "7f6a25e20deab4ec32f411dc5f179428a140dca7844f7c7d36aae348f0f88459",
|
"scripts/snapshot_agent.py": "a15a939e62af7dfe150ef79c44db71e18b713c1bac72cbd508f1298c42d584b8",
|
||||||
"scripts/snapshot-to-task.ts": "ec6f270f7e479bdac4da70811ed4bf6edac86e53455590bff5bbdf14f73966d4",
|
"scripts/snapshot-to-task.ts": "e60d0e18615123f8d36d614bd72237350d84f1e997aa543081ccc0c456556b67",
|
||||||
"scripts/stage-atomic-rubric.ts": "008132bb078face75011b727d17354711e2550d33ea55ae12d00cb29be9a4dee",
|
"scripts/stage-atomic-rubric.ts": "008132bb078face75011b727d17354711e2550d33ea55ae12d00cb29be9a4dee",
|
||||||
"scripts/stamp-trial-inputs.ts": "7b9780d8062e99999dd7e2c63f4eca1c4f043b46641881db725b1f1980b47633",
|
"scripts/stamp-trial-inputs.ts": "7b9780d8062e99999dd7e2c63f4eca1c4f043b46641881db725b1f1980b47633",
|
||||||
"scripts/str_replace_editor": "943bcf04b010bba7c6a71ed32b5384a00c5ba0ca10a4ef249f0359af6bbbfb0f",
|
"scripts/str_replace_editor": "943bcf04b010bba7c6a71ed32b5384a00c5ba0ca10a4ef249f0359af6bbbfb0f",
|
||||||
@@ -50,7 +52,7 @@
|
|||||||
"scripts/str_replace_editor_vendor/base.py": "469db977748364092c977c436f29df4f45f46ae7b511ea6f1e0289e5e7e3e9d2",
|
"scripts/str_replace_editor_vendor/base.py": "469db977748364092c977c436f29df4f45f46ae7b511ea6f1e0289e5e7e3e9d2",
|
||||||
"scripts/str_replace_editor_vendor/edit.py": "778784efd243cae802f0c472a3daadd054a972bcdf07fa66bf0b07f46920a093",
|
"scripts/str_replace_editor_vendor/edit.py": "778784efd243cae802f0c472a3daadd054a972bcdf07fa66bf0b07f46920a093",
|
||||||
"scripts/str_replace_editor_vendor/run.py": "0bae4a787dfe7ad00ad2732c4cbb857701545324b21295771113d1d2e0d42295",
|
"scripts/str_replace_editor_vendor/run.py": "0bae4a787dfe7ad00ad2732c4cbb857701545324b21295771113d1d2e0d42295",
|
||||||
"scripts/submit-task.ts": "995d46d36e91917635987b5efbba7ee3ff41bbe3271b375e2ff8feb5b4f1ff25",
|
"scripts/submit-task.ts": "493152f871bbe2b833210700cf24456e82041da710791c1d42579a362813e3ba",
|
||||||
"scripts/toolset_note_browser.md": "4f58008444ef854454420c299b268135a82c9d324a840744fd0460d51e9edd98",
|
"scripts/toolset_note_browser.md": "4f58008444ef854454420c299b268135a82c9d324a840744fd0460d51e9edd98",
|
||||||
"scripts/toolset_note_read.md": "bb969d696898e2ecadb81b875beaef3ae3b11df1961d35fd43114c748c83c3ce",
|
"scripts/toolset_note_read.md": "bb969d696898e2ecadb81b875beaef3ae3b11df1961d35fd43114c748c83c3ce",
|
||||||
"scripts/toolset_note.md": "7dff7325f48f1fa0e01ca5794c866ab5e61098d3a7aeae69b21331110bb1ac04",
|
"scripts/toolset_note.md": "7dff7325f48f1fa0e01ca5794c866ab5e61098d3a7aeae69b21331110bb1ac04",
|
||||||
@@ -139,8 +139,8 @@ The same goes for the toolkit's own `scripts/`. Nothing in there belongs to a ta
|
|||||||
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
||||||
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
||||||
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
||||||
report on these too; restoring means re-extracting the toolkit zip over your copy, which
|
report on these too; restoring means re-extracting the zip this toolkit came from over
|
||||||
leaves your tasks, snapshots and reference runs alone.
|
your copy, which leaves your tasks, snapshots and reference runs alone.
|
||||||
|
|
||||||
## Reference-data corpus (only some toolkits)
|
## Reference-data corpus (only some toolkits)
|
||||||
|
|
||||||
@@ -1,5 +1,30 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
|
||||||
|
- **Fixed: on the uberduck-polyglot toolkit, `run-app uberduck` now installs the frontend dependencies before starting the app.** Before, setup skipped that step and the frontend failed to start.
|
||||||
|
- **`submit-task.ts` now leaves the staged atomic-rubric copies out of the package, so you no longer need to run `stage-atomic-rubric.ts --restore` first.**
|
||||||
|
- **Fixed: on the swingbell-polyglot toolkit, `ai-usecase` task images now install its app's dependencies.** The app lives in `vite-project/`, and the image used to install only the empty top-level `package.json`; a task you created on an earlier release keeps its own `environment/Dockerfile`.
|
||||||
|
|
||||||
|
- **Fixed: on the swingbell-polyglot toolkit, `run-app` now starts `book-my-minutes-onboarding`, `book-my-minutes-onboarding-expert-app`, `on-boarding-ui-ssr` and `ai-usecase`, and prints the address that works for apps served under a sub-path, such as `/care` or `/expert`.** In Explore, the company's live hostnames now resolve nowhere, so a running app can no longer load data from the production site.
|
||||||
|
- **Fixed: on polyglot toolkits, `run-app` now installs and starts a member whose app lives in a subfolder of its repo from that subfolder.** Before, those members installed nothing or said they had no dev-server script.
|
||||||
|
- **Fixed: on the speedwell-polyglot toolkit, `mix test` in `strongsuit_phx` no longer fails four `cronofy_account_controller_test` tests with 401 in the Explore container.** The container no longer sets `API_AUTH_TOKEN` or `PHX_AUTH_TOKEN`, so the app, the Phoenix server and its tests all use the same built-in default. Reported by a worker.
|
||||||
|
- **Fixed: on the swingbell-polyglot toolkit, the Java services now build in Explore.** The Explore container installs the shared libraries they depend on (`common-repository`, `common-aws-service`, `jasper-report`, `jwt-encryption-decryption`, and the `book-my-minutes-*` versions of the first two) when it is created, so `mvn package` no longer fails on missing `com.swingbell` dependencies.
|
||||||
|
- **Fixed: on the swingbell-polyglot toolkit, `meetings`, `nhcx-provider` and `book-my-minutes-jobs` tasks now build against the shared-library versions their code is written for.** Before, their task images failed to compile; re-run `build-workspace.sh` on an existing task for one of them to pick this up.
|
||||||
|
- **Fixed: a snapshot no longer loses the output of the first of two tool calls the agent made at once.** Those commands used to show no output when the task resumed; snapshots taken before this release keep the gaps. Reported by a worker.
|
||||||
|
- **Fixed: on the potion-polyglot toolkit, the `potion-wp-site` task image now builds on x86_64 and includes the Claude CLI, so its tasks can be run and regraded.** A task you created on an earlier release keeps its own `environment/Dockerfile`. Reported by a worker.
|
||||||
|
- **`harbor-regrade` accepts `HARBOR_GRADER_MODE=atomic` and `=holistic`** (also `atomic-scalar` and `holistic-one-shot`), the names the two scores go by. The old names still work.
|
||||||
|
- **Fixed: a test command that hangs no longer leaves a trial ungraded.** Each check in `test-commands.sh` now stops after 30 minutes (`SIGNAL_TIMEOUT_SEC`), and the grader sees it as timed out with the output so far.
|
||||||
|
- **When the Codex grader fails, its error now shows the reason Codex gave**, not just an exit status.
|
||||||
|
- **Fixed: the Codex grader no longer fails with `401 Incorrect API key` on task images that set a placeholder `OPENAI_API_KEY` for the app.** It now uses the key that matches the proxy route it grades through.
|
||||||
|
- **Fixed: on the zeta-polyglot toolkit, `read_sql` in `zeta-predictors` no longer raises `ValueError: orient 'record' not understood`.** Every `zeta_ds` reader that goes through it, such as `get_table_size` and `count`, failed on the image's pandas 2.x before running its query; a task you created on an earlier release keeps its own copy of the code. Reported by a worker.
|
||||||
|
- **A task image now fails to build when its Codex CLI is missing or older than 0.158.0, the oldest the grader accepts.** Before, the build carried on and every grade then failed; an image cached with an older Codex rebuilds.
|
||||||
|
- **Fixed: local trials now give Opus the same 1M-token context window as Explore.** Before, trials ran with 200k and compacted a long Explore session before the first reply.
|
||||||
|
- **`submit-task.ts` refuses a task that holds one of your API keys in a file you wrote, such as `workspace.patch`, and names the file.** A key that ends up in a session file or reference run is removed for you.
|
||||||
|
- **Fixed: in local trials, the agent can no longer find what `workspace.patch` or a hand edit changed by sorting files by time or permissions.** `harbor-run` now gives every workspace file the same modified time and removes group write. Reported by a worker.
|
||||||
|
- **The toolkit now unzips into a folder named with its version, so a new release sits next to the old one instead of on top of it.** Stop the old toolkit's Explore container before you start the new one, since both use the same port.
|
||||||
|
- **Fixed: on the palolo-031 toolkit, an agent that starts the app with `pnpm run dev` now gets the client on port 3000, which the API accepts.** A task you created on an earlier release keeps its own `environment/Dockerfile`. Reported by a worker.
|
||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
- New tasks are graded with **GPT-6 Sol / high / one sample**.
|
- New tasks are graded with **GPT-6 Sol / high / one sample**.
|
||||||
@@ -137,8 +137,8 @@ The same goes for the toolkit's own `scripts/`. Nothing in there belongs to a ta
|
|||||||
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
||||||
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
||||||
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
||||||
report on these too; restoring means re-extracting the toolkit zip over your copy, which
|
report on these too; restoring means re-extracting the zip this toolkit came from over
|
||||||
leaves your tasks, snapshots and reference runs alone.
|
your copy, which leaves your tasks, snapshots and reference runs alone.
|
||||||
|
|
||||||
## Reference-data corpus (only some toolkits)
|
## Reference-data corpus (only some toolkits)
|
||||||
|
|
||||||
@@ -335,8 +335,9 @@ The toolkit's own `scripts/` are checked the same way, and for the same reason.
|
|||||||
aren't part of any task, which is what makes an edit there easy to miss — but
|
aren't part of any task, which is what makes an edit there easy to miss — but
|
||||||
`build-workspace.sh` stages each task's `tests/test-commands.sh`, fills in parts of its
|
`build-workspace.sh` stages each task's `tests/test-commands.sh`, fills in parts of its
|
||||||
`environment/Dockerfile`, and records the checksums a reviewer reads. Restoring means
|
`environment/Dockerfile`, and records the checksums a reviewer reads. Restoring means
|
||||||
re-extracting the toolkit zip over your copy; your tasks, snapshots and reference runs
|
re-extracting the zip this toolkit came from over your copy; your tasks, snapshots and
|
||||||
are untouched by that. Scripts you add yourself are yours and are never reported.
|
reference runs are untouched by that. Scripts you add yourself are yours and are never
|
||||||
|
reported.
|
||||||
|
|
||||||
## Key principles
|
## Key principles
|
||||||
|
|
||||||
@@ -363,7 +364,7 @@ See `.claude/skills/` for detailed guidance (available in the Authoring containe
|
|||||||
|
|
||||||
**The database isn't running after a reboot or container stop** — Re-run `npx @devcontainers/cli up`; whichever database your toolkit uses is restarted automatically on every container start. (You no longer need to start it by hand.)
|
**The database isn't running after a reboot or container stop** — Re-run `npx @devcontainers/cli up`; whichever database your toolkit uses is restarted automatically on every container start. (You no longer need to start it by hand.)
|
||||||
|
|
||||||
**Ports stopped working after a toolkit upgrade** — Docker fixes a container's port mappings when it's first created, so an old container won't pick up new ports just from `up`. Recreate it: `npx @devcontainers/cli up --remove-existing-container`. This wipes the container's Claude history, so run `/create-snapshot:snapshot` first if there's a conversation you want to keep.
|
**"port is already allocated" after a toolkit upgrade** — The old toolkit's Explore container still holds the port. Stop it with `docker stop $(docker ps -q --filter publish=<port>)`, using the port from the error.
|
||||||
|
|
||||||
**Snapshot command not found** — Make sure you're in the Explore container, not the Authoring container.
|
**Snapshot command not found** — Make sure you're in the Explore container, not the Authoring container.
|
||||||
|
|
||||||
488
worker-toolkit-potion-polyglot-v1.0.1/code-diff.txt
Normal file
488
worker-toolkit-potion-polyglot-v1.0.1/code-diff.txt
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/index.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/index.js
|
||||||
|
index 0995e23..84f050a 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/index.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/index.js
|
||||||
|
@@ -10,6 +10,7 @@ const sqs = require('../app/services/sqs')
|
||||||
|
const s3 = require('../app/services/s3')
|
||||||
|
const voiceCloningService = require('./voice_cloning')
|
||||||
|
const userAudioProfileService = require('./user_audio_profile')
|
||||||
|
+const { requireUserId } = require('../worker_tenant')
|
||||||
|
|
||||||
|
AWS.config.update({ region: 'us-west-2' })
|
||||||
|
const sqsQueueUrl = process.env.SQS_URL
|
||||||
|
@@ -101,7 +102,7 @@ const processQueue = () => {
|
||||||
|
const receiptHandle = response.Messages[0].ReceiptHandle
|
||||||
|
console.log('job===', job)
|
||||||
|
|
||||||
|
- const { metadata, input, _id, userAudioProfileId } = job._doc
|
||||||
|
+ const { metadata, input, _id, userAudioProfileId, userId } = job._doc
|
||||||
|
console.log('userAudioProfileId', userAudioProfileId)
|
||||||
|
console.log('_id', _id)
|
||||||
|
const { env } = job
|
||||||
|
@@ -126,9 +127,25 @@ const processQueue = () => {
|
||||||
|
? cloudFrontUrlStaging
|
||||||
|
: cloudFrontUrlDev
|
||||||
|
|
||||||
|
+ let authorized = false
|
||||||
|
try {
|
||||||
|
await sqs.deleteMessageFromSQS(sqsQueueUrl, receiptHandle)
|
||||||
|
|
||||||
|
+ requireUserId(userId)
|
||||||
|
+ const cloningRecord = await voiceCloningService.read({
|
||||||
|
+ _id,
|
||||||
|
+ userId,
|
||||||
|
+ userAudioProfileId,
|
||||||
|
+ })
|
||||||
|
+ const audioProfile = await userAudioProfileService.read({
|
||||||
|
+ _id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
+ })
|
||||||
|
+ if (!cloningRecord || !audioProfile) {
|
||||||
|
+ throw new Error('Voice cloning job records do not belong to the job user')
|
||||||
|
+ }
|
||||||
|
+ authorized = true
|
||||||
|
+
|
||||||
|
const { directoryName } = metadata
|
||||||
|
console.log('directoryName', directoryName)
|
||||||
|
const logPath = `/mnt/efs/potion-voice/${env}/${directoryName}`
|
||||||
|
@@ -136,11 +153,19 @@ const processQueue = () => {
|
||||||
|
fs.mkdirSync(logPath, { recursive: true })
|
||||||
|
}
|
||||||
|
// update the db model to processing
|
||||||
|
- await voiceCloningService.update({ _id, status: 'processing' })
|
||||||
|
- await userAudioProfileService.update({
|
||||||
|
+ const processingClone = await voiceCloningService.update({
|
||||||
|
+ _id,
|
||||||
|
+ userId,
|
||||||
|
+ status: 'processing',
|
||||||
|
+ })
|
||||||
|
+ const processingProfile = await userAudioProfileService.update({
|
||||||
|
_id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
status: 'processing',
|
||||||
|
})
|
||||||
|
+ if (!processingClone || !processingProfile) {
|
||||||
|
+ throw new Error('Voice cloning job records are no longer available to the job user')
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// create directory for userid-useraudioprofileid if not exist
|
||||||
|
const rootPath = `/tmp/${directoryName}`
|
||||||
|
@@ -240,7 +265,7 @@ const processQueue = () => {
|
||||||
|
console.timeEnd(VOICE_MINIMIZE_LABEL)
|
||||||
|
|
||||||
|
// Add the code to update location of generated model and status into DB
|
||||||
|
- await voiceCloningService.update({ _id, status: 'completed' })
|
||||||
|
+ await voiceCloningService.update({ _id, userId, status: 'completed' })
|
||||||
|
|
||||||
|
const training_model_path = {
|
||||||
|
voice_model_path: `${resultsPath}/${generatedDirectoryName}/checkpoint_365200.pth`,
|
||||||
|
@@ -252,6 +277,7 @@ const processQueue = () => {
|
||||||
|
|
||||||
|
await userAudioProfileService.update({
|
||||||
|
_id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
status: 'completed',
|
||||||
|
training_model_path,
|
||||||
|
})
|
||||||
|
@@ -273,6 +299,7 @@ const processQueue = () => {
|
||||||
|
// add S3 path to user audio profile model
|
||||||
|
await userAudioProfileService.update({
|
||||||
|
_id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
training_model_s3_path,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
@@ -285,11 +312,14 @@ const processQueue = () => {
|
||||||
|
Bugsnag.notify(error)
|
||||||
|
|
||||||
|
// update the db to set status as error
|
||||||
|
- await voiceCloningService.update({ _id, status: 'error' })
|
||||||
|
- await userAudioProfileService.update({
|
||||||
|
- _id: userAudioProfileId,
|
||||||
|
- status: 'error',
|
||||||
|
- })
|
||||||
|
+ if (authorized) {
|
||||||
|
+ await voiceCloningService.update({ _id, userId, status: 'error' })
|
||||||
|
+ await userAudioProfileService.update({
|
||||||
|
+ _id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
+ status: 'error',
|
||||||
|
+ })
|
||||||
|
+ }
|
||||||
|
|
||||||
|
resolve() // to continue working on new jobs
|
||||||
|
}
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/user_audio_profile/user_audio_profile_service.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
index e76643d..244a848 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
const StringifyUtils = require('../../app/services/utils/logService')
|
||||||
|
+const { tenantFilter } = require('../../worker_tenant')
|
||||||
|
|
||||||
|
const create = (UserAudioProfileModel) => async (data) => {
|
||||||
|
try {
|
||||||
|
@@ -32,7 +33,7 @@ const insertMany = (UserAudioProfileModel) => async (data) => {
|
||||||
|
const read = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModel = await UserAudioProfileModel.findOne({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundModel
|
||||||
|
@@ -49,7 +50,7 @@ const read = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
const find = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModels = await UserAudioProfileModel.find({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundModels
|
||||||
|
@@ -65,9 +66,10 @@ const find = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
|
||||||
|
const update = (UserAudioProfileModel) => async (data) => {
|
||||||
|
try {
|
||||||
|
+ const { _id, userId, ...changes } = data
|
||||||
|
const updatedModel = await UserAudioProfileModel.findOneAndUpdate(
|
||||||
|
- { _id: data._id },
|
||||||
|
- data,
|
||||||
|
+ { ...tenantFilter({ _id, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
{
|
||||||
|
new: true,
|
||||||
|
}
|
||||||
|
@@ -86,7 +88,7 @@ const update = (UserAudioProfileModel) => async (data) => {
|
||||||
|
const remove = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await UserAudioProfileModel.findOneAndUpdate(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
@@ -108,7 +110,7 @@ const remove = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
const removeMany = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await UserAudioProfileModel.updateMany(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/voice_cloning/voice_cloning_service.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/voice_cloning/voice_cloning_service.js
|
||||||
|
index 329638e..8e7bd55 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/voice_cloning/voice_cloning_service.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-cloning-job-handler/voice_cloning/voice_cloning_service.js
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
const StringifyUtils = require('../../app/services/utils/logService')
|
||||||
|
+const { tenantFilter } = require('../../worker_tenant')
|
||||||
|
|
||||||
|
const create = (VoiceCloningModel) => async (data) => {
|
||||||
|
try {
|
||||||
|
@@ -32,7 +33,7 @@ const insertMany = (VoiceCloningModel) => async (data) => {
|
||||||
|
const read = (VoiceCloningModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModel = await VoiceCloningModel.findOne({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundModel
|
||||||
|
@@ -49,7 +50,7 @@ const read = (VoiceCloningModel) => async (filter) => {
|
||||||
|
const find = (VoiceCloningModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModels = await VoiceCloningModel.find({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundModels
|
||||||
|
@@ -65,9 +66,10 @@ const find = (VoiceCloningModel) => async (filter) => {
|
||||||
|
|
||||||
|
const update = (VoiceCloningModel) => async (data) => {
|
||||||
|
try {
|
||||||
|
+ const { _id, userId, ...changes } = data
|
||||||
|
const updatedModel = await VoiceCloningModel.findOneAndUpdate(
|
||||||
|
- { _id: data._id },
|
||||||
|
- data,
|
||||||
|
+ { ...tenantFilter({ _id, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
{
|
||||||
|
new: true,
|
||||||
|
}
|
||||||
|
@@ -87,7 +89,7 @@ const update = (VoiceCloningModel) => async (data) => {
|
||||||
|
const remove = (VoiceCloningModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await VoiceCloningModel.findOneAndUpdate(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
@@ -109,7 +111,7 @@ const remove = (VoiceCloningModel) => async (filter) => {
|
||||||
|
const removeMany = (VoiceCloningModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await VoiceCloningModel.updateMany(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/index.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/index.js
|
||||||
|
index 862300f..7cb19f0 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/index.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/index.js
|
||||||
|
@@ -11,6 +11,7 @@ const recordingModel = require('./recording')
|
||||||
|
const recordingSalutationModel = require('./recording_salutation')
|
||||||
|
const jobService = require('./job')
|
||||||
|
const salutationService = require('./salutation')
|
||||||
|
+const { requireUserId } = require('../worker_tenant')
|
||||||
|
let throttleMessageFetching = true
|
||||||
|
AWS.config.update({ region: 'us-west-2' })
|
||||||
|
const sqsQueueUrl = process.env.SQS_URL
|
||||||
|
@@ -72,6 +73,7 @@ const processQueue = () => {
|
||||||
|
await sqs.deleteMessageFromSQS(sqsQueueUrl, receiptHandle)
|
||||||
|
|
||||||
|
const {
|
||||||
|
+ userId,
|
||||||
|
userAudioProfileId,
|
||||||
|
text,
|
||||||
|
firstName,
|
||||||
|
@@ -91,14 +93,17 @@ const processQueue = () => {
|
||||||
|
console.log('DB_URI ', DB_URI)
|
||||||
|
await connectDB(DB_URI)
|
||||||
|
|
||||||
|
+ requireUserId(userId)
|
||||||
|
+
|
||||||
|
// read the path for the training model for the this users audio profile
|
||||||
|
|
||||||
|
- const userAudioProfile = await userAudioProfileService.find({
|
||||||
|
+ const userAudioProfile = await userAudioProfileService.read({
|
||||||
|
_id: userAudioProfileId,
|
||||||
|
+ userId,
|
||||||
|
status: 'completed',
|
||||||
|
})
|
||||||
|
if (userAudioProfile) {
|
||||||
|
- const { training_model_path, userId } = userAudioProfile[0]
|
||||||
|
+ const { training_model_path } = userAudioProfile
|
||||||
|
const {
|
||||||
|
voice_model_light_path,
|
||||||
|
voice_model_config_light_path,
|
||||||
|
@@ -151,11 +156,13 @@ const processQueue = () => {
|
||||||
|
// update the dynamic recordings for the current dynamic video with salutation url
|
||||||
|
const salutationToUpdate = await recordingSalutationModel.findOne({
|
||||||
|
_id: salutationId,
|
||||||
|
+ userId,
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const recordingToUpdate = await recordingModel.findOne({
|
||||||
|
_id: recordingId,
|
||||||
|
+ userId,
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
@@ -169,6 +176,8 @@ const processQueue = () => {
|
||||||
|
await recordingSalutationModel.findOneAndUpdate(
|
||||||
|
{
|
||||||
|
_id: salutationId,
|
||||||
|
+ userId,
|
||||||
|
+ deleted: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/job/job_service.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/job/job_service.js
|
||||||
|
index 44189af..ff53150 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/job/job_service.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/job/job_service.js
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
const StringifyUtils = require('../../app/services/utils/logService')
|
||||||
|
+const { tenantFilter } = require('../../worker_tenant')
|
||||||
|
|
||||||
|
const create = (Job) => async (jobData) => {
|
||||||
|
try {
|
||||||
|
@@ -32,7 +33,7 @@ const insertMany = (Job) => async (jobData) => {
|
||||||
|
const read = (Job) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundJob = await Job.findOne({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundJob
|
||||||
|
@@ -49,7 +50,7 @@ const read = (Job) => async (filter) => {
|
||||||
|
const find = (Job) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundJobs = await Job.find({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundJobs
|
||||||
|
@@ -65,9 +66,12 @@ const find = (Job) => async (filter) => {
|
||||||
|
|
||||||
|
const update = (Job) => async (job) => {
|
||||||
|
try {
|
||||||
|
- const updatedJob = await Job.findOneAndUpdate({ _id: job._id }, job, {
|
||||||
|
- new: true,
|
||||||
|
- })
|
||||||
|
+ const { _id, userId, ...changes } = job
|
||||||
|
+ const updatedJob = await Job.findOneAndUpdate(
|
||||||
|
+ { ...tenantFilter({ _id, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
+ { new: true }
|
||||||
|
+ )
|
||||||
|
return updatedJob
|
||||||
|
} catch (error) {
|
||||||
|
const details = { job }
|
||||||
|
@@ -82,7 +86,7 @@ const update = (Job) => async (job) => {
|
||||||
|
const remove = (Job) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedJob = await Job.findOneAndUpdate(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
@@ -104,7 +108,7 @@ const remove = (Job) => async (filter) => {
|
||||||
|
const removeMany = (Job) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedJob = await Job.updateMany(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/salutation/salutation_service.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/salutation/salutation_service.js
|
||||||
|
index 2d84f78..ad58f0d 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/salutation/salutation_service.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/salutation/salutation_service.js
|
||||||
|
@@ -1,4 +1,7 @@
|
||||||
|
+const { tenantFilter, requireUserId } = require('../../worker_tenant')
|
||||||
|
+
|
||||||
|
const create = (Salutation) => async (salutationData, userId) => {
|
||||||
|
+ requireUserId(userId)
|
||||||
|
const newSalutation = new Salutation({ ...salutationData, userId })
|
||||||
|
const savedSalutation = await newSalutation.save()
|
||||||
|
return savedSalutation
|
||||||
|
@@ -6,7 +9,7 @@ const create = (Salutation) => async (salutationData, userId) => {
|
||||||
|
|
||||||
|
const read = (Salutation) => async (filter) => {
|
||||||
|
const foundSalutation = await Salutation.findOne({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundSalutation
|
||||||
|
@@ -14,29 +17,33 @@ const read = (Salutation) => async (filter) => {
|
||||||
|
|
||||||
|
const find = (Salutation) => async (filter) => {
|
||||||
|
const foundSalutations = await Salutation.find({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false,
|
||||||
|
})
|
||||||
|
return foundSalutations
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = (Salutation) => async (salutation, userId) => {
|
||||||
|
+ const { _id, userId: ignoredUserId, ...changes } = salutation.toObject
|
||||||
|
+ ? salutation.toObject()
|
||||||
|
+ : salutation
|
||||||
|
const updatedSalutation = await Salutation.findOneAndUpdate(
|
||||||
|
- { _id: salutation._id, userId },
|
||||||
|
- salutation,
|
||||||
|
+ { ...tenantFilter({ _id, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
{ new: true }
|
||||||
|
)
|
||||||
|
return updatedSalutation
|
||||||
|
}
|
||||||
|
|
||||||
|
-const modify = (Salutation) => async (salutation) => {
|
||||||
|
- const findQuery = salutation._id
|
||||||
|
- ? { _id: salutation._id }
|
||||||
|
+const modify = (Salutation) => async (salutation, userId) => {
|
||||||
|
+ const { _id, userId: ignoredUserId, ...changes } = salutation
|
||||||
|
+ const findQuery = _id
|
||||||
|
+ ? { _id }
|
||||||
|
: { transcriptId: salutation.transcriptId }
|
||||||
|
|
||||||
|
const updatedSalutation = await Salutation.findOneAndUpdate(
|
||||||
|
- findQuery,
|
||||||
|
- salutation,
|
||||||
|
+ { ...tenantFilter({ ...findQuery, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
{ new: true }
|
||||||
|
)
|
||||||
|
return updatedSalutation
|
||||||
|
@@ -63,7 +70,7 @@ const updateOrCreate =
|
||||||
|
|
||||||
|
const remove = (Salutation) => async (filter, userId) => {
|
||||||
|
const updatedSalutation = await Salutation.findOneAndUpdate(
|
||||||
|
- { ...filter, userId },
|
||||||
|
+ { ...tenantFilter({ ...filter, userId }), deleted: false },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true,
|
||||||
|
diff --git a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/user_audio_profile/user_audio_profile_service.js b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
index 18416d7..22acbf8 100644
|
||||||
|
--- a/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
+++ b/worker-toolkit-potion-polyglot-v1.0.1/repos/potion-voice/voice-synthsizer-job-handler/user_audio_profile/user_audio_profile_service.js
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
const StringifyUtils = require('../../app/services/utils/logService')
|
||||||
|
+const { tenantFilter } = require('../../worker_tenant')
|
||||||
|
|
||||||
|
const create = (UserAudioProfileModel) => async (data) => {
|
||||||
|
try {
|
||||||
|
@@ -32,7 +33,7 @@ const insertMany = (UserAudioProfileModel) => async (data) => {
|
||||||
|
const read = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModel = await UserAudioProfileModel.findOne({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false
|
||||||
|
})
|
||||||
|
return foundModel
|
||||||
|
@@ -49,7 +50,7 @@ const read = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
const find = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const foundModels = await UserAudioProfileModel.find({
|
||||||
|
- ...filter,
|
||||||
|
+ ...tenantFilter(filter),
|
||||||
|
deleted: false
|
||||||
|
})
|
||||||
|
return foundModels
|
||||||
|
@@ -66,9 +67,10 @@ const find = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
const update = (UserAudioProfileModel) => async (data) => {
|
||||||
|
console.log('ua data', data)
|
||||||
|
try {
|
||||||
|
+ const { _id, userId, ...changes } = data
|
||||||
|
const updatedModel = await UserAudioProfileModel.findOneAndUpdate(
|
||||||
|
- { _id: data._id },
|
||||||
|
- data,
|
||||||
|
+ { ...tenantFilter({ _id, userId }), deleted: false },
|
||||||
|
+ { $set: changes },
|
||||||
|
{
|
||||||
|
new: true
|
||||||
|
}
|
||||||
|
@@ -88,7 +90,7 @@ const update = (UserAudioProfileModel) => async (data) => {
|
||||||
|
const remove = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await UserAudioProfileModel.findOneAndUpdate(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true
|
||||||
|
@@ -110,7 +112,7 @@ const remove = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
const removeMany = (UserAudioProfileModel) => async (filter) => {
|
||||||
|
try {
|
||||||
|
const updatedModel = await UserAudioProfileModel.updateMany(
|
||||||
|
- { ...filter },
|
||||||
|
+ { ...tenantFilter(filter) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
deleted: true
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"args": {
|
"args": {
|
||||||
"TOOLKIT_BUILD_ID": "1790712369311-8xr6mu"
|
"TOOLKIT_BUILD_ID": "1791247286386-y2uh1u"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appPort": [
|
"appPort": [
|
||||||
@@ -438,6 +438,39 @@ print('admin user ready')
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# The swingbell Java services resolve sibling members' com.swingbell* SNAPSHOT libs only from a
|
||||||
|
# local Maven repo. The book-my-minutes-* twins reuse those coordinates, so they get their own.
|
||||||
|
_sbl_install() { # <local repo> <member>[@<revision>]...
|
||||||
|
local repo_local="$1" m rev src; shift
|
||||||
|
for m in "$@"; do
|
||||||
|
rev=HEAD; case "$m" in *@*) rev=${m#*@}; m=${m%@*} ;; esac
|
||||||
|
[ -e "/workspace/repos/$m/.git" ] || continue
|
||||||
|
src=$(mktemp -d)
|
||||||
|
( git -C "/workspace/repos/$m" archive "$rev" | tar -x -C "$src" \
|
||||||
|
&& cd "$src" && mvn -q -B -Dstyle.color=never -DskipTests -Dmaven.repo.local="$repo_local" install ) \
|
||||||
|
|| echo "WARNING: could not install $m into $repo_local; services that depend on it won't build until it is" >&2
|
||||||
|
rm -rf "$src"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
_sbl_use() { # <member> <local repo>
|
||||||
|
local d="/workspace/repos/$1"
|
||||||
|
[ -f "$d/pom.xml" ] || return 0
|
||||||
|
mkdir -p "$d/.mvn" "$d/.git/info"
|
||||||
|
printf -- '-Dmaven.repo.local=%s\n' "$2" > "$d/.mvn/maven.config"
|
||||||
|
grep -qxF '.mvn/maven.config' "$d/.git/info/exclude" 2>/dev/null \
|
||||||
|
|| printf '\n# raccoon-explore: selects this service'"'"'s local Maven repo\n.mvn/maven.config\n' >> "$d/.git/info/exclude"
|
||||||
|
}
|
||||||
|
if [ -n "$IS_POLYGLOT" ] && grep -qs 'com\.swingbell' /workspace/repos/common-repository/pom.xml; then
|
||||||
|
_sbl_install "$HOME/.m2/repository" common-repository common-aws-service jwt-encryption-decryption reports
|
||||||
|
_sbl_install "$HOME/.m2/bmm-repository" book-my-minutes-common-repository book-my-minutes-common-aws-service reports
|
||||||
|
for d in /workspace/repos/book-my-minutes-* /workspace/repos/meetings; do _sbl_use "$(basename "$d")" "$HOME/.m2/bmm-repository"; done
|
||||||
|
# These two were written against a different revision of their library than the one pinned.
|
||||||
|
_sbl_install "$HOME/.m2/nhcx-provider-repository" common-repository@208aea7be jwt-encryption-decryption
|
||||||
|
_sbl_use nhcx-provider "$HOME/.m2/nhcx-provider-repository"
|
||||||
|
_sbl_install "$HOME/.m2/bmm-jobs-repository" book-my-minutes-common-repository@f15e7c128
|
||||||
|
_sbl_use book-my-minutes-jobs "$HOME/.m2/bmm-jobs-repository"
|
||||||
|
fi
|
||||||
|
|
||||||
# Mirror Harbor's reduced toolset in the interactive Explore session. Use
|
# Mirror Harbor's reduced toolset in the interactive Explore session. Use
|
||||||
# Harbor's /opt path when available, but fall back to a user-writable path for
|
# Harbor's /opt path when available, but fall back to a user-writable path for
|
||||||
# generic devcontainer fixtures that run lifecycle hooks as a non-root user.
|
# generic devcontainer fixtures that run lifecycle hooks as a non-root user.
|
||||||
@@ -528,8 +561,8 @@ bash /workspace/welcome.sh explore 2>/dev/null
|
|||||||
|
|
||||||
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
||||||
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
||||||
_WID="w-mun3wr6n-v83f"
|
_WID="w-muvydvub-qn4j"
|
||||||
_VER="1.0.0"
|
_VER="1.0.1"
|
||||||
_CT="explore"
|
_CT="explore"
|
||||||
_RP=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').repo)}catch{}" 2>/dev/null)
|
_RP=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').repo)}catch{}" 2>/dev/null)
|
||||||
_SID="$(date +%s)-$$"
|
_SID="$(date +%s)-$$"
|
||||||
@@ -415,6 +415,24 @@ while (current) {
|
|||||||
current = byUuid[current]?.parentUuid || null;
|
current = byUuid[current]?.parentUuid || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parallel tool calls can be written call, call, result, result: the first result then hangs
|
||||||
|
// off the first call on a side branch the walk above never visits, so add those back.
|
||||||
|
const blocksOf = (e) => (Array.isArray(e?.message?.content) ? e.message.content : []);
|
||||||
|
const activeToolUseIds = new Set();
|
||||||
|
for (const uuid of activeBranchUuids) {
|
||||||
|
for (const b of blocksOf(byUuid[uuid])) if (b?.type === 'tool_use') activeToolUseIds.add(b.id);
|
||||||
|
}
|
||||||
|
for (const e of Object.values(byUuid)) {
|
||||||
|
if (activeBranchUuids.has(e.uuid) || !activeBranchUuids.has(e.parentUuid)) continue;
|
||||||
|
const blocks = blocksOf(e);
|
||||||
|
if (
|
||||||
|
blocks.length &&
|
||||||
|
blocks.every((b) => b?.type === 'tool_result' && activeToolUseIds.has(b.tool_use_id))
|
||||||
|
) {
|
||||||
|
activeBranchUuids.add(e.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Step 4: filter — keep entries on the active branch.
|
// Step 4: filter — keep entries on the active branch.
|
||||||
//
|
//
|
||||||
// Claude Code writes several bookkeeping entry types alongside the message
|
// Claude Code writes several bookkeeping entry types alongside the message
|
||||||
@@ -743,7 +761,7 @@ fi
|
|||||||
# Install conversation so the authoring harness can resume it
|
# Install conversation so the authoring harness can resume it
|
||||||
${
|
${
|
||||||
IS_CLAUDE
|
IS_CLAUDE
|
||||||
? `ENCODED_CWD=$(echo "$PWD" | sed 's|/|-|g; s|^-||')
|
? `ENCODED_CWD=$(echo "$PWD" | sed 's|[^a-zA-Z0-9]|-|g; s|^-||')
|
||||||
DEST_DIR="$HOME/.claude/projects/-$ENCODED_CWD"
|
DEST_DIR="$HOME/.claude/projects/-$ENCODED_CWD"
|
||||||
mkdir -p "$DEST_DIR"
|
mkdir -p "$DEST_DIR"
|
||||||
cp "$SCRIPT_DIR/session.jsonl" "$DEST_DIR/$SESSION_UUID.jsonl"
|
cp "$SCRIPT_DIR/session.jsonl" "$DEST_DIR/$SESSION_UUID.jsonl"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Plugin-side re-export, so snapshot-to-task.ts resolves `./lib/secret-scrub`
|
||||||
|
* both here and in the toolkit's flat scripts/ dir.
|
||||||
|
*/
|
||||||
|
export * from '../../../../static/scripts/lib/secret-scrub';
|
||||||
@@ -162,10 +162,13 @@ function replacePrefixAtBoundary(haystack: string, needle: string, replacement:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Must match Claude Code's `.claude/projects/` folder names. */
|
||||||
|
const encodeProjectDir = (p: string) => p.replace(/[^a-zA-Z0-9]/g, '-');
|
||||||
|
|
||||||
/** Replace a prefix and its dash-encoded form (`.claude/projects/<encoded>/`). */
|
/** Replace a prefix and its dash-encoded form (`.claude/projects/<encoded>/`). */
|
||||||
function stripBothForms(haystack: string, needle: string, replacement: string): string {
|
function stripBothForms(haystack: string, needle: string, replacement: string): string {
|
||||||
const out = literalReplaceAll(haystack, needle, replacement);
|
const out = literalReplaceAll(haystack, needle, replacement);
|
||||||
return literalReplaceAll(out, needle.replace(/\//g, '-'), replacement.replace(/\//g, '-'));
|
return literalReplaceAll(out, encodeProjectDir(needle), replacement.replace(/\//g, '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): SanitizeResult {
|
export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): SanitizeResult {
|
||||||
@@ -193,7 +196,7 @@ export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): S
|
|||||||
// EVERY root before ANY home dir: a home pass run between roots would rewrite a
|
// EVERY root before ANY home dir: a home pass run between roots would rewrite a
|
||||||
// sibling root's own prefix, leaving it unmatched when its turn came.
|
// sibling root's own prefix, leaving it unmatched when its turn came.
|
||||||
for (const prefix of prefixes) {
|
for (const prefix of prefixes) {
|
||||||
const encodedPrefix = prefix.replace(/\//g, '-');
|
const encodedPrefix = encodeProjectDir(prefix);
|
||||||
working = replacePrefixAtBoundary(working, prefix, placeholder);
|
working = replacePrefixAtBoundary(working, prefix, placeholder);
|
||||||
working = literalReplaceAll(working, encodedPrefix, placeholder.replace(/\//g, '-'));
|
working = literalReplaceAll(working, encodedPrefix, placeholder.replace(/\//g, '-'));
|
||||||
prefixStripped ??= prefix;
|
prefixStripped ??= prefix;
|
||||||
@@ -206,7 +209,7 @@ export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): S
|
|||||||
.filter((h): h is string => h !== null && !prefixes.includes(h))
|
.filter((h): h is string => h !== null && !prefixes.includes(h))
|
||||||
);
|
);
|
||||||
for (const homeDir of homeDirs) {
|
for (const homeDir of homeDirs) {
|
||||||
const encodedHomeDir = homeDir.replace(/\//g, '-');
|
const encodedHomeDir = encodeProjectDir(homeDir);
|
||||||
working = replacePrefixAtBoundary(working, homeDir, HOME_DIR_PLACEHOLDER);
|
working = replacePrefixAtBoundary(working, homeDir, HOME_DIR_PLACEHOLDER);
|
||||||
working = literalReplaceAll(working, encodedHomeDir, HOME_DIR_PLACEHOLDER.replace(/\//g, '-'));
|
working = literalReplaceAll(working, encodedHomeDir, HOME_DIR_PLACEHOLDER.replace(/\//g, '-'));
|
||||||
homeDirStripped ??= homeDir;
|
homeDirStripped ??= homeDir;
|
||||||
@@ -26,6 +26,7 @@ import { stripAuthoringScaffolding, truncationIndex, turnsFromLines } from './ha
|
|||||||
// This script must not call cpSync — it fails EACCES on a macOS docker bind mount.
|
// This script must not call cpSync — it fails EACCES on a macOS docker bind mount.
|
||||||
import { holisticRubricScaffoldFor } from './holistic-rubric-scaffold';
|
import { holisticRubricScaffoldFor } from './holistic-rubric-scaffold';
|
||||||
import { copyTree } from './lib/copy-tree';
|
import { copyTree } from './lib/copy-tree';
|
||||||
|
import { readEnvSecrets, scrubTaskSecrets } from './lib/secret-scrub';
|
||||||
import { collectCwds, sanitizeSessionJsonl } from './sanitize-session-jsonl';
|
import { collectCwds, sanitizeSessionJsonl } from './sanitize-session-jsonl';
|
||||||
|
|
||||||
// --- CLI ---
|
// --- CLI ---
|
||||||
@@ -576,6 +577,13 @@ if (existsSync(sessionDir) && statSync(sessionDir).isDirectory()) {
|
|||||||
mkdirSync(join(taskDir, 'environment', 'session'), { recursive: true });
|
mkdirSync(join(taskDir, 'environment', 'session'), { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Explore agent can print the .env it runs with (`env`, `cat .env`), so its keys can be in
|
||||||
|
// the capture. The scrub is silent: the worker didn't put them there and has nothing to do.
|
||||||
|
const secretScan = scrubTaskSecrets(taskDir, readEnvSecrets(repoRoot));
|
||||||
|
for (const file of secretScan.flagged) {
|
||||||
|
log.warn({ file }, 'This file holds an API key from your .env. Remove it before you submit.');
|
||||||
|
}
|
||||||
|
|
||||||
// The harness that captured the snapshot; the trial runs this one.
|
// The harness that captured the snapshot; the trial runs this one.
|
||||||
const harness =
|
const harness =
|
||||||
typeof metadata.harness === 'string' && metadata.harness ? metadata.harness : 'claude-code';
|
typeof metadata.harness === 'string' && metadata.harness ? metadata.harness : 'claude-code';
|
||||||
1
worker-toolkit-potion-polyglot-v1.0.1/explore/repos
Symbolic link
1
worker-toolkit-potion-polyglot-v1.0.1/explore/repos
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/home/eric/workspaces/dataannotation/project-2/worker-toolkit-potion-polyglot-v1.0.1/repos
|
||||||
@@ -319,6 +319,18 @@ _node_bin() {
|
|||||||
d=$(ls -d "$nvm_dir"/versions/node/v"$major".* 2>/dev/null | sort -V | tail -1)
|
d=$(ls -d "$nvm_dir"/versions/node/v"$major".* 2>/dev/null | sort -V | tail -1)
|
||||||
[ -n "$d" ] && printf '%s/bin' "$d"
|
[ -n "$d" ] && printf '%s/bin' "$d"
|
||||||
}
|
}
|
||||||
|
# First dev-server script <dir>/package.json defines. `next start` serves a production build that
|
||||||
|
# a fresh checkout doesn't have, so a Next app boots `dev` instead.
|
||||||
|
_dev_script() {
|
||||||
|
node -e "const s=(require('$1/package.json').scripts)||{};const o=['start','dev','develop','serve'].filter(k=>s[k]&&!(k==='start'&&/^next start/.test(s[k])&&s.dev));if(o[0])process.stdout.write(o[0])" 2>/dev/null
|
||||||
|
}
|
||||||
|
# Path the app serves under in dev: a path "homepage" (CRA) or a Next.js basePath, e.g. /app.
|
||||||
|
_homepage_path() {
|
||||||
|
local p
|
||||||
|
p=$(node -e "const h=(require('$1/package.json').homepage)||'';let p=h;try{p=new URL(h).pathname}catch{};if(/^\/[^/]/.test(p))process.stdout.write(p.replace(/\/$/,''))" 2>/dev/null)
|
||||||
|
[ -n "$p" ] || p=$(cat "$1"/next.config.* 2>/dev/null | sed -nE "s/^[[:space:]]*basePath:[[:space:]]*['\"](\/[^'\"]+)['\"].*/\1/p" | head -1)
|
||||||
|
printf '%s' "$p"
|
||||||
|
}
|
||||||
# Symlink ./node_modules (cwd = the dir being installed) to a container-local tree keyed by
|
# Symlink ./node_modules (cwd = the dir being installed) to a container-local tree keyed by
|
||||||
# <key> — see the ENFILE rationale at the call site. The target must itself be named
|
# <key> — see the ENFILE rationale at the call site. The target must itself be named
|
||||||
# `node_modules` (Node resolves the symlink, then walks ancestors for that literal name),
|
# `node_modules` (Node resolves the symlink, then walks ancestors for that literal name),
|
||||||
@@ -637,9 +649,9 @@ setup_repo() {
|
|||||||
else
|
else
|
||||||
_mark_ctr_nodeps "$repo"
|
_mark_ctr_nodeps "$repo"
|
||||||
printf " ${YELLOW}\xe2\x9a\xa0 %s: dependencies did not install${RESET} \xe2\x80\x94 explore-only in this container.\n ${GRAY}Reading the code, git and the editor still work; running the app or its tests will not.\n Usually a pin with no build for this machine's architecture. To retry: rm %s/%s.done${RESET}\n" "$repo" "$CTR_MARKER_DIR" "$repo"
|
printf " ${YELLOW}\xe2\x9a\xa0 %s: dependencies did not install${RESET} \xe2\x80\x94 explore-only in this container.\n ${GRAY}Reading the code, git and the editor still work; running the app or its tests will not.\n Usually a pin with no build for this machine's architecture. To retry: rm %s/%s.done${RESET}\n" "$repo" "$CTR_MARKER_DIR" "$repo"
|
||||||
fi
|
|
||||||
_mark_ctr_setup "$repo"; return 0
|
_mark_ctr_setup "$repo"; return 0
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
_py_have "$ver" || { printf " ${GRAY}(Python %s not in this image; skipping deps \xe2\x80\x94 explore-only)${RESET}\n" "$ver"; _mark_ctr_setup "$repo"; return 0; }
|
_py_have "$ver" || { printf " ${GRAY}(Python %s not in this image; skipping deps \xe2\x80\x94 explore-only)${RESET}\n" "$ver"; _mark_ctr_setup "$repo"; return 0; }
|
||||||
# Some poetry repos depend on sibling repos via `git = "ssh://git@github.com/AskZeta/<name>.git"`,
|
# Some poetry repos depend on sibling repos via `git = "ssh://git@github.com/AskZeta/<name>.git"`,
|
||||||
# which can't resolve in the container (no SSH key, no network). The deps are TRANSITIVE
|
# which can't resolve in the container (no SSH key, no network). The deps are TRANSITIVE
|
||||||
@@ -666,7 +678,8 @@ setup_repo() {
|
|||||||
# pip-installed as a package. Mirrors the harbor build.
|
# pip-installed as a package. Mirrors the harbor build.
|
||||||
poetry install --no-interaction --no-root; \
|
poetry install --no-interaction --no-root; \
|
||||||
elif [ -f requirements.txt ]; then pip install -r requirements.txt; \
|
elif [ -f requirements.txt ]; then pip install -r requirements.txt; \
|
||||||
elif [ -f setup.py ]; then pip install -e .; else true; fi; } ) || return 1 ;;
|
elif [ -f setup.py ]; then pip install -e .; else true; fi; } ) || return 1
|
||||||
|
fi ;;
|
||||||
rust)
|
rust)
|
||||||
command -v cargo >/dev/null 2>&1 || { printf " ${GRAY}(Rust not in this image; skipping build \xe2\x80\x94 explore-only)${RESET}\n"; _mark_ctr_setup "$repo"; return 0; }
|
command -v cargo >/dev/null 2>&1 || { printf " ${GRAY}(Rust not in this image; skipping build \xe2\x80\x94 explore-only)${RESET}\n"; _mark_ctr_setup "$repo"; return 0; }
|
||||||
# Build to a container-local target dir (same ENFILE/bind-mount rationale as
|
# Build to a container-local target dir (same ENFILE/bind-mount rationale as
|
||||||
@@ -696,7 +709,15 @@ setup_repo() {
|
|||||||
printf " ${GRAY}preparing %s (one-time; details in ${RESET}${GRAY}run-app --logs${RESET}${GRAY})\xe2\x80\xa6${RESET}\n" "$repo"
|
printf " ${GRAY}preparing %s (one-time; details in ${RESET}${GRAY}run-app --logs${RESET}${GRAY})\xe2\x80\xa6${RESET}\n" "$repo"
|
||||||
if ( cd "$dir" \
|
if ( cd "$dir" \
|
||||||
&& export PATH="${spath:+$spath:}$PATH" \
|
&& export PATH="${spath:+$spath:}$PATH" \
|
||||||
&& case "$kind" in ruby) export RBENV_VERSION="$ver" ;; python) export PYENV_VERSION="$ver" ;; esac \
|
&& case "$kind" in
|
||||||
|
ruby) export RBENV_VERSION="$ver" ;;
|
||||||
|
python)
|
||||||
|
if _py_uv_ok "$ver"; then
|
||||||
|
. "$(_uv_venv_dir "$repo")/bin/activate"
|
||||||
|
else
|
||||||
|
export PYENV_VERSION="$ver"
|
||||||
|
fi ;;
|
||||||
|
esac \
|
||||||
&& { for kv in $bootenv; do export "$kv"; done; } \
|
&& { for kv in $bootenv; do export "$kv"; done; } \
|
||||||
&& eval "$setupcmd" ) > "$slog" 2>&1; then
|
&& eval "$setupcmd" ) > "$slog" 2>&1; then
|
||||||
printf " ${GRAY}\xe2\x9c\x93 %s prepared${RESET}\n" "$repo"
|
printf " ${GRAY}\xe2\x9c\x93 %s prepared${RESET}\n" "$repo"
|
||||||
@@ -793,10 +814,8 @@ start_poly() {
|
|||||||
if [ -n "$startcmd" ]; then
|
if [ -n "$startcmd" ]; then
|
||||||
cmd="env $bootenv PORT=3000 BROWSER=none HOST=0.0.0.0 $startcmd"
|
cmd="env $bootenv PORT=3000 BROWSER=none HOST=0.0.0.0 $startcmd"
|
||||||
else
|
else
|
||||||
local s2=""
|
local s2
|
||||||
for s2 in start dev develop serve; do
|
s2=$(_dev_script "$dir")
|
||||||
if node -e "process.exit((((require('$dir/package.json')||{}).scripts)||{})['$s2']?0:1)" 2>/dev/null; then break; else s2=""; fi
|
|
||||||
done
|
|
||||||
if [ -z "$s2" ]; then
|
if [ -z "$s2" ]; then
|
||||||
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
||||||
return 0
|
return 0
|
||||||
@@ -811,10 +830,7 @@ start_poly() {
|
|||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
# CRA / generic: first dev-server script the repo defines, bound to :3000.
|
# CRA / generic: first dev-server script the repo defines, bound to :3000.
|
||||||
local s
|
sc=$(_dev_script "$dir")
|
||||||
for s in start dev develop serve; do
|
|
||||||
if node -e "process.exit((((require('$dir/package.json')||{}).scripts)||{})['$s']?0:1)" 2>/dev/null; then sc="$s"; break; fi
|
|
||||||
done
|
|
||||||
if [ -z "$sc" ]; then
|
if [ -z "$sc" ]; then
|
||||||
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
||||||
return 0
|
return 0
|
||||||
@@ -840,7 +856,11 @@ start_poly() {
|
|||||||
craenv="CI=true DANGEROUSLY_DISABLE_HOST_CHECK=true"
|
craenv="CI=true DANGEROUSLY_DISABLE_HOST_CHECK=true"
|
||||||
case "${ver%%.*}" in 1[7-9]|[2-9][0-9]) craenv="NODE_OPTIONS=--openssl-legacy-provider $craenv" ;; esac
|
case "${ver%%.*}" in 1[7-9]|[2-9][0-9]) craenv="NODE_OPTIONS=--openssl-legacy-provider $craenv" ;; esac
|
||||||
fi
|
fi
|
||||||
cmd="env $bootenv $craenv PATH=$nbin:\$PATH PORT=3000 BROWSER=none HOST=0.0.0.0 yarn $sc"
|
# Vite ignores PORT/HOST and listens on localhost:5173, which the published port can't reach.
|
||||||
|
local viteargs=""
|
||||||
|
node -e "process.exit(/^vite( |$)(?!build|preview)/.test((require('$dir/package.json').scripts||{})['$sc']||'')?0:1)" 2>/dev/null \
|
||||||
|
&& viteargs=" --host 0.0.0.0 --port 3000"
|
||||||
|
cmd="env $bootenv $craenv PATH=$nbin:\$PATH PORT=3000 BROWSER=none HOST=0.0.0.0 yarn $sc$viteargs"
|
||||||
fi ;;
|
fi ;;
|
||||||
python)
|
python)
|
||||||
if _ctr_nodeps "$repo"; then
|
if _ctr_nodeps "$repo"; then
|
||||||
@@ -890,9 +910,9 @@ start_poly() {
|
|||||||
|| printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx database prep failed \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
|| printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx database prep failed \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||||
if [ -d "$phx_dir/deps" ] && [ -d "$phx_dir/_build" ]; then
|
if [ -d "$phx_dir/deps" ] && [ -d "$phx_dir/_build" ]; then
|
||||||
printf " ${CYAN}\xe2\x96\xb6${RESET} starting strongsuit_phx (elixir)\xe2\x80\xa6\n"
|
printf " ${CYAN}\xe2\x96\xb6${RESET} starting strongsuit_phx (elixir)\xe2\x80\xa6\n"
|
||||||
# Derived, not a second env var: the app sends PHX_AUTH_TOKEN and the phx plug
|
# The app sends PHX_AUTH_TOKEN and the phx plug compares API_AUTH_TOKEN; both default
|
||||||
# compares against API_AUTH_TOKEN, and a drift shows up only as silent 401s.
|
# to the same value, so pass one only when the other was set.
|
||||||
_spawn phx "$phx_dir" "env MIX_ENV=dev PHX_PORT=$COMPANION_PORT API_AUTH_TOKEN=${PHX_AUTH_TOKEN:-dummy} mix phx.server"
|
_spawn phx "$phx_dir" "env MIX_ENV=dev PHX_PORT=$COMPANION_PORT ${PHX_AUTH_TOKEN:+API_AUTH_TOKEN=$PHX_AUTH_TOKEN} mix phx.server"
|
||||||
_wait_tcp "$COMPANION_PORT" 45 || printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx didn't come up \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
_wait_tcp "$COMPANION_PORT" 45 || printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx didn't come up \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||||
else
|
else
|
||||||
printf " ${GRAY}strongsuit_phx isn't built \xe2\x80\x94 the backend on :%s will be absent.\n" "$COMPANION_PORT"
|
printf " ${GRAY}strongsuit_phx isn't built \xe2\x80\x94 the backend on :%s will be absent.\n" "$COMPANION_PORT"
|
||||||
@@ -908,6 +928,8 @@ start_poly() {
|
|||||||
local landing=""
|
local landing=""
|
||||||
case "$repo" in
|
case "$repo" in
|
||||||
strongsuit-app) landing="/dev-login" ;;
|
strongsuit-app) landing="/dev-login" ;;
|
||||||
|
ABDM-FE) landing="/app/login" ;;
|
||||||
|
*) [ "$kind" = node ] && landing=$(_homepage_path "$dir") ;;
|
||||||
esac
|
esac
|
||||||
printf " ${CYAN}\xe2\x9c\x85 %s is up${RESET} open ${CYAN}http://localhost:%s%s${RESET}\n" "$repo" "$CLIENT_HOST_PORT" "$landing"
|
printf " ${CYAN}\xe2\x9c\x85 %s is up${RESET} open ${CYAN}http://localhost:%s%s${RESET}\n" "$repo" "$CLIENT_HOST_PORT" "$landing"
|
||||||
# Per-member "how do I actually get in" notes. Only members whose landing page needs
|
# Per-member "how do I actually get in" notes. Only members whose landing page needs
|
||||||
@@ -922,11 +944,15 @@ start_poly() {
|
|||||||
printf " Auth0 and cannot work offline.${RESET}\n"
|
printf " Auth0 and cannot work offline.${RESET}\n"
|
||||||
;;
|
;;
|
||||||
ABDM-FE)
|
ABDM-FE)
|
||||||
printf " ${GRAY}This app is served under a ${RESET}${GRAY}/app${RESET}${GRAY} basename, so the bare URL above renders\n"
|
printf " ${GRAY}Sign-in calls hosted services that aren't reachable offline, so the\n"
|
||||||
printf " nothing. Open ${RESET}${CYAN}http://localhost:%s/app/login${RESET}${GRAY} instead.\n" "$CLIENT_HOST_PORT"
|
|
||||||
printf " Sign-in itself calls hosted services that aren't reachable offline, so the\n"
|
|
||||||
printf " login page is as far as you can get — read and edit the code from there.${RESET}\n"
|
printf " login page is as far as you can get — read and edit the code from there.${RESET}\n"
|
||||||
;;
|
;;
|
||||||
|
book-my-minutes-app)
|
||||||
|
printf " ${GRAY}This is the signed-in dashboard: every page needs a session, and signing in happens\n"
|
||||||
|
printf " on a separate hosted app that isn't reachable offline, so the page above stays\n"
|
||||||
|
printf " blank. Read and edit the code instead, or run ${RESET}${GRAY}book-my-minutes-onboarding${RESET}${GRAY} to see the\n"
|
||||||
|
printf " public side of the product.${RESET}\n"
|
||||||
|
;;
|
||||||
search-api-v2)
|
search-api-v2)
|
||||||
printf " ${GRAY}Browse and try the API at ${RESET}${CYAN}http://localhost:%s/docs${RESET}${GRAY}.\n" "$CLIENT_HOST_PORT"
|
printf " ${GRAY}Browse and try the API at ${RESET}${CYAN}http://localhost:%s/docs${RESET}${GRAY}.\n" "$CLIENT_HOST_PORT"
|
||||||
printf " Sign-in goes through a hosted identity provider that isn't reachable offline,\n"
|
printf " Sign-in goes through a hosted identity provider that isn't reachable offline,\n"
|
||||||
Binary file not shown.
@@ -271,9 +271,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"defaultRepo": "potion-app",
|
"defaultRepo": "potion-app",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"buildSha": "f62b06f",
|
"buildSha": "5e48703",
|
||||||
"packedFrom": "565c9589c46926ee3025f82d28f31be0aae007e8",
|
"packedFrom": "9b0c19e8f35875c162ad4e6129dfbdcbfc5f177c",
|
||||||
"blockedHosts": [
|
"blockedHosts": [
|
||||||
"sendpotion.com",
|
"sendpotion.com",
|
||||||
"www.sendpotion.com",
|
"www.sendpotion.com",
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"stampedAt": "2026-09-29T20:06:24.427Z",
|
"stampedAt": "2026-10-06T00:41:40.440Z",
|
||||||
"files": {
|
"files": {
|
||||||
"tests/test.sh": "67d84a6d694718a777dfb9d79cb629206f769b92c67d66e19d9bb98bda168d04",
|
"tests/test.sh": "32eb923e2772d1a7a0393f333adeff5eb33f68132cb5cadf4480ce1eb0ad5329",
|
||||||
"tests/grader-system-prompt-consolidated.md": "032ce032728a8c0b2717478b929dbd7535e07c96ffe2e991097dd2c233543275"
|
"tests/grader-system-prompt-consolidated.md": "032ce032728a8c0b2717478b929dbd7535e07c96ffe2e991097dd2c233543275"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user