application_feedback ยท diff
git:20261101.a39418b to git:20261104.acd24f3
49 added, 38 removed. Audit A to A.
---
name: application_feedback
- description: Draft the English feedback email for one startup from its latest submission review, for the SICTIC screener to proofread and paste into Dealum. Use after submission_ready; bulk refresh runs it for Application-stage startups.
+ description: Draft and email feedback for one startup with a fresh submission_ready review to configured internal reviewers. Bulk refresh invokes it per Application-stage startup.
---
# Application feedback
- Draft the feedback email for one startup from its stored submission review.
+ One startup, one feedback email, one task for the reviewer.
## Inputs and outputs
- The async `application_feedback(startup)` returns `list[InsightFile]`: the
- draft `application-feedback-<startup>-<model>.md` in the startup's insights
- folder, or an empty list when the review proposes no concerns. A draft only
- contains that startup's own information.
-
- `feedback_state(startup)` reads the latest review, its proposed action and the
- draft that matches it, without generating anything. `None` as draft means no
- concerns, or no current draft yet. [distribution_policy](../distribution_policy/SKILL.md)
- uses it for the screener summary.
+ `application_feedback(startup, *, email="send")` returns `list[InsightFile]`:
+ the full email content in `application-feedback-<startup>-<model>.md`, or `[]`
+ when there is no fresh review or no proposed concerns. The existing filename,
+ manual precedence and draft cache are preserved. Recipients proofread the draft
+ and send it to the applicant themselves.
## Workflow and dependencies
- Bulk refresh runs this step for Application-stage startups after
- `submission-ready`, its registered dependency. A direct call uses the latest
- stored review from `submission_ready.latest_response` without checking its
- freshness, so run `submission_ready` first when the review must be current.
+ Bulk refresh invokes this single-startup operation after submission-ready.
+ It never runs a review or loops over applications. When a stored review exists,
+ synchronize the dataset and require a fresh review through
+ `submission_ready.latest_response(require_fresh=True)`. Missing or stale reviews
+ produce no draft and no email. Fresh means reusable for the current audit,
+ configuration, stage and indexed sources; it need not have been generated in
+ this invocation. A changed audit invalidates the older response when a newer
+ review run fails before completing its response.
- Read the action with `submission_ready.proposed_action`. Only `Send concerns to
- startup` gets a draft: `generate_markdown` writes it in English, following
- `config/application_feedback/email_instructions.md`. The greeting uses the
- startup name of the latest Dealum application in the dossier. The model only
- receives the concerns read with `submission_ready.stated_concerns`, not the
- checklist, to reduce unsupported additions.
+ Only `Send concerns to startup` gets a draft. The model receives only the stated
+ concerns, following `config/application_feedback/email_instructions.md`.
+ The greeting uses the stored Dealum startup name. SCREENER_SIGNATURE supplies
+ the signature, with `[Screener name]` as the fallback. The formatting reviewer
+ does not establish factual fidelity; the human reviewer checks the content.
+ Unchanged inputs reuse the draft; manual drafts retain precedence.
- The draft is signed with `SCREENER_SIGNATURE` from `.env`, or with the
- placeholder `[Screener name]` for the screener to replace when it is empty.
- A reviewer requires between one and as many numbered points as there are
- concerns, and that signature. These are formatting checks; they do not
- establish that every concern is covered or that no concern was invented. The
- screener must verify the draft against the review before sending it.
+ The comma-separated APPLICATION_FEEDBACK_RECIPIENTS controls internal delivery.
+ Empty or unset saves and returns the draft without sending. By default, a new,
+ changed or undelivered draft is sent in full through send_gmail, one email per
+ startup to all configured recipients. No email is sent to the applicant.
+ `email="off"` and `email="dry-run"` save and return the Markdown without sending
+ or recording delivery. Changing draft instructions redrafts without rerunning
+ the review, provided that review remains fresh.
- A stored or manual draft is reused while the instructions, the startup name,
- the signature and the concerns are unchanged. Changing the instructions only
- redrafts; it does not invalidate the review.
+ ## Delivery tracking and failures
- ## Side effects and failure behavior
+ Delivery receipts remain at
+ `storage/generated/application-feedback-runs/insights/email-delivery.json`.
+ The existing application/recipient keys and schema are preserved, including the
+ legacy `summary` field, which now records the draft path. Prior receipts prevent
+ duplicates after upgrade. Content and recipient changes are eligible again;
+ recipient ordering does not matter.
- Reads the stored review and calls the configured model when a new draft is
- needed. It does not access Dealum, send email or change any stage. A missing
- review, a review without a proposed action, or a review that proposes sending
- concerns without stating any raises; generation failures propagate.
+ The shared lock covers the decision, send and acknowledgement. An attempt is
+ recorded as uncertain before sending. Success records sent. Uncertain deliveries
+ are logged and held for inspection, while the draft is still returned and other
+ startups continue normally. Check Sent mail before marking an uncertain entry
+ sent or removing it to permit a new attempt; stop the scheduled job while doing
+ so. A missing gws binary is known to precede delivery and permits a later retry.
+ Other failures are not retried automatically. Unreadable receipts, invalid review
+ contents, synchronization errors and generation/send failures propagate.
## Usage
```bash
conda run -n sictic-env python -m skills.application_feedback --startup "Example Startup"
+ conda run -n sictic-env python -m skills.application_feedback --startup "Example Startup" --email dry-run
```
- Normally bulk refresh runs this step. There is no harness command.
+ The nightly schedule only needs bulk_refresh. Replace SCREENER_EMAILS with
+ APPLICATION_FEEDBACK_RECIPIENTS on the runtime host before enabling delivery.
+ No separate distribution command remains. This skill has no harness command.
## References
- [Implementation](application_feedback.py), [CLI](__main__.py)
- - [Email instructions](../../config/application_feedback/email_instructions.md)
+ - [Delivery receipts](delivery.py)
- [Submission review](../submission_ready/SKILL.md)
- - [Screener summary and email](../distribution_policy/SKILL.md)
+ - [Email sending](../send_gmail/SKILL.md)